michael michael - 1 month ago 6
C Question

Usage of Literal arrays or compounds

I have a struct

typedef struct
{
int num_bytes; // number of relevant bytes
void * bytes_p; // pointer to bytes
} BYTES_T;


which is passed as parameter to a lot of functions on many places.

Usually I use it as follows:

uint8_t my_array[] = {0x01, 0x03, 0xff} ; // example array
BYTES_T my_bytes;
my_bytes.bytes_p = my_array;
my_bytes.num_bytes= sizeof(my_array);

...

foo(&my_bytes); // call a function


To make parts of my code more readable I would like to avoid simultaneous creation of both the array AND the struct within the same context.

So as a first trial I played around with a macro, using compound literals:

#define ARRAYINFO(A) &((BYTES_T ){.bytes_p = ((A)), .num_bytes = sizeof(((A)))})


and use it like

foo(ARRAYINFO(my_array));


This works - when an array is passed. But when I pass the pointer to an array, it will - of course - produce nonsense:

uint8_t * array_pointer = my_array; // this is allowed
foo(ARRAYINFO(array_pointer )); // nonsense for num_bytes because sizeof()


Therefore, this is dangerous and not an option.

NextI thought about a construct to create the struct without creating the array explicitly:

#define CREATE_BYTES(A) &((BYTES_T ){.bytes_p = ((A)), .num_bytes = sizeof((A))})

BYTES_T my_bytes = CREATE_BYTES(((uint8_t []){1,2,3,4,5}));


This seems to work, but I think that the "internal" array , representing the passed literal is created twice in memory (the macro evaluates it twice).

Is there a solution for such idea?

Answer

This seems to work, but I think that the "internal" array , representing the passed literal is created twice in memory (the macro evaluates it twice).

From the C99 standard:

6.5.3.4/2

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

So A is evaluated only once in your macro:

#define CREATE_BYTES(A) &((BYTES_T ){.bytes_p = ((A)), .num_bytes = sizeof((A))})
Comments