sizeof compound literal array
Asked Answered
M

1

8

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
Matador answered 29/11, 2016 at 16:58 Comment(3)
Possible duplicate of can I reduce a long array initialization to a short initializer list in C?Aylmar
If you strip down your problem to a minimal reproducible example as required, you end up at the duplicate. I still think my answer is the most clear and easiest solution. Just adopt to your problem. If the fields are not to be modified, you should use the const qualifier (correctly!).Aylmar
The only potential trick here is that you'll need to enclose the array literal in (extra) parentheses when it is used as an argument to a macro such as Olaf describes in his referenced answer. The parentheses will prevent the commas in the literal itself from being taken as macro argument separators.Idden
F
3

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++;
    }
}
Fret answered 29/11, 2016 at 17:30 Comment(1)
"Do you really need to know the size of it?" -- Not really. Thanks. :-)Chambermaid

© 2022 - 2024 — McMap. All rights reserved.