Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sizeof compound literal array

I'm trying to statically allocate some structures, each containing two members: a pointer to an array of structures, and the size of that array.

Here's a working version of the code:

#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))

struct conf_element {
        char *key;
        enum conf_elem_type val_type;
        void *val_p;
        tok_t *(*fn_p)(const char *js, jsmntok_t *tok);
};

struct conf_schema {
        struct conf_element *conf_elems;
        size_t size;
};

struct conf_element conf_schema_antennae_elems[] = {
        {"key1_nm", LEAF_INT, NULL, NULL},
        {"key2_nm", LEAF_INT, NULL, NULL}
};

struct conf_schema conf_schema_antennae = {
        conf_schema_antennae_elems,
        ARRAY_SIZE(conf_schema_antennae_elems)
};

But rather than defining the array separately and then referencing that array when defining the structure, I'd like to initialize the pointer with an array literal in order to contain it all in the structure definition for the sake of what I believe to be increased readability:

struct conf_schema conf_schema_antennae = {
        (struct conf_element []) {
                {"key1_nm", LEAF_INT, NULL, NULL},
                {"key2_nm", LEAF_INT, NULL, NULL}
        },
        /* the size of that ^ compound literal goes here */
};

Is it possible to automatically get the size of that array literal at compile time? (Or am I abusing the language and making things harder than they should be?)

EDIT: Based on Olaf's answer to a similar question and John Bollinger's comment, here's what I ended up with:

#define S(arr) {arr, ARRAY_SIZE(arr)}

struct conf_schema conf_schema_antennae = S((
        (struct conf_element []) {
                {"key1_nm", LEAF_INT, NULL, NULL},
                {"key2_nm", LEAF_INT, NULL, NULL}
        }
));

#undef S
like image 428
Chase Patterson Avatar asked Nov 29 '16 16:11

Chase Patterson


People also ask

What is compound literals?

A compound literal is a postfix expression that provides an unnamed object whose value is given by an initializer list. The C99 language feature allows you to pass parameters to functions without the need for temporary variables.

Does C++ have compound literals?

In C++, a compound literal designates a temporary object, which only lives until the end of its full-expression. As a result, well-defined C code that takes the address of a subobject of a compound literal can be undefined in C++, so the C++ compiler rejects the conversion of a temporary array to a pointer.

Is array a literal in C?

Compound literals were introduced in C99 standard of C. Compound literals feature allows us to create unnamed objects with given list of initialized values. In the above example, an array is created without any name. Address of first element of array is assigned to pointer p.


1 Answers

You can't know know the size of a compound literal array, because its variable name is hidden.

Also struct conf_element *conf_elems is a pointer and the macro ARRAY_SIZE cannot measure the length of the real array.

You can see the name of the hidden variable if compiled with -g. It will show in the debug information of the executable a variable named __compond_literal.###.

I suggest you a workaround: Do you really need to know the size of it in the client code? If not, try this:

struct conf_schema conf_schema_antennae = {
        (struct conf_element []) {
                {"key1_nm", LEAF_INT, NULL, NULL},
                {"key2_nm", LEAF_INT, NULL, NULL},
                {0, 0, 0, 0} /* Place holder for the end of the array */
        }
};

void client_code ()
{
    struct conf_element *p_elems = conf_schema_antennae.conf_elems;

    while (p_elems->key)
    {
     /* ... */
     p_elems++;
    }
}
like image 176
Felipe Lavratti Avatar answered Oct 02 '22 22:10

Felipe Lavratti