jeremy
jeremy

Reputation: 4681

Generate nested constant arrays in C at compile time

I'm trying to generate a large constant lookup table at compile time in C (C99), and each entry to the lookup table has a pointer to another const array. I'd like to be able to build all of these arrays all at once, but this isn't possible because a brace initialiser can't be used for a pointer. Is there some preprocessor macro or other trick I can use to define "anonymous" arrays or something similar so that I can include them in a nested data structure?

I've created an example below, showing what I am currently doing, and also what I am trying to do.

typedef enum {
    RED = 0,
    GREEN,
    BLUE,
    PURPLE,
    YELLOW
} colours_t;

typedef struct {
    const char *name;

    const size_t number_of_preferences;
    const colours_t *ordered_preferences;
} colour_preferences_t;


// this way works, but is tedious
const colours_t bob_preferences[] = {RED, GREEN};
const colours_t alice_preferences[] = {BLUE, PURPLE, YELLOW};
const colours_t eve_preferences[] = {YELLOW, RED};

const colour_preferences_t array_of_preferences[3] = {
        {"Bob", 2, bob_preferences},
        {"Alice", 3, alice_preferences},
        {"Eve", 2, eve_preferences}
};


// this is how I'd like to do it (but it isn't valid)
const colour_preferences_t array_of_preferences_invalid[3] = {
        {"Bob", 2, {RED, GREEN}},
        {"Alice", 3, {BLUE, PURPLE, YELLOW}},
        {"Eve", 1, {YELLOW, RED}},
};

Update: Thanks to the answers below, I have worked out a solution. And using a varadic macro, I can even drop typing out the size explicitly:

#define PREFERENCE_LIST(...) sizeof((colours_t[]) { __VA_ARGS__ })/sizeof(colours_t), (colours_t[]){ __VA_ARGS__ }

const colour_preferences_t array_of_preferences_short[3] = {
        {"Bob", PREFERENCE_LIST(RED, GREEN)},
        {"Alice", PREFERENCE_LIST(BLUE, PURPLE, YELLOW)},
        {"Eve", PREFERENCE_LIST(YELLOW, RED)}
};

Upvotes: 1

Views: 183

Answers (2)

Ctx
Ctx

Reputation: 18410

It should work using a compound literal like this:

const colour_preferences_t array_of_preferences_invalid[3] = {
        {"Bob", 2, (colours_t[]){RED, GREEN}},
        {"Alice", 3, (colours_t[]){BLUE, PURPLE, YELLOW}},
        {"Eve", 1, (colours_t[]){YELLOW, RED}},
};

You can read the details about compound literals here

Upvotes: 3

0___________
0___________

Reputation: 67835

you need to create the object, and pointer to this object has to be the initializer of this field. You can archive it by using the compound literals

const colour_preferences_t array_of_preferences_invalid[3] = {
        {"Bob", 2, ( const colours_t[]){RED, GREEN}},
        {"Alice", 3,  (const colours_t[]){BLUE, PURPLE, YELLOW}},
        {"Eve", 1, (const colours_t[]){YELLOW, RED}},
};

Upvotes: 3

Related Questions