在C语言中,在编译时生成嵌套的常量数组。

huangapple go评论90阅读模式
英文:

Generate nested constant arrays in C at compile time

问题

我试图在C(C99)中在编译时生成一个大的常量查找表,查找表中的每个条目都有一个指向另一个常量数组的指针。我想一次性构建所有这些数组,但这是不可能的,因为花括号初始化器不能用于指针。是否有一些预处理宏或其他技巧,我可以使用来定义“匿名”数组或类似的东西,以便我可以将它们包含在嵌套数据结构中?

我已经创建了下面的示例,展示了我当前正在做的事情,以及我试图做的事情。

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;


// 这种方式可以工作,但很繁琐
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}
};


// 这是我想要的方式(但它无效)
const colour_preferences_t array_of_preferences_invalid[3] = {
    {"Bob", 2, {RED, GREEN}},
    {"Alice", 3, {BLUE, PURPLE, YELLOW}},
    {"Eve", 1, {YELLOW, RED}},
};

更新:多亏了下面的答案,我已经找到了解决方案。并且使用可变参数宏,甚至可以省去显式输入大小:

#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)}
};
英文:

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)}
};

答案1

得分: 3

你需要创建对象,并且该对象的指针必须成为该字段的初始化器。您可以通过使用复合字面值来实现它。

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}},
};
英文:

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}},
};

</details>



# 答案2
**得分**: 3

使用复合字面量可以像这样工作:

```c
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}},
};

你可以在这里阅读有关复合字面量的详细信息。

英文:

It should work using a compound literal like this:

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

You can read the details about compound literals here

huangapple
  • 本文由 发表于 2020年1月3日 19:56:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/59578209.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定