基于编译时判断初始化正确的联合体成员
根据常量/变量动态初始化联合体成员
需要实现一个宏,根据传入的表达式是编译时常量还是变量,初始化联合体的不同成员。已找到GCC扩展__builtin_constant_p()可判断表达式是否为常量(返回1表示常量,0表示变量),但不清楚如何基于此结果生成对应的联合体初始化代码。
原始尝试代码
#define TOKEN 10 typedef union { void* pv_variable; int literal; } foo_t; foo_t test_array[] = { {.literal = 500}, {.pv_variable = NULL} // 以下写法无效,如何使其生效? // // {(TOKEN == 10) ? (.literal) : (.pv_variable) = 10}, // {__builtin_choose_expr(__builtin_constant_p(TOKEN), .literal = 10, .pv_variable = NULL)}, // {. ## __builtin_choose_expr(__builtin_constant_p(TOKEN), literal, pv_variable) = 10}, };
目标实现需求
#define INIT_UNION(val) /* TODO: */ #define SOME_VARIABLE some_variable #define SOME_CONSTANT 10 int some_variable = 20; typedef union { void* pv_variable; int literal; } foo_t; foo_t test_array[] = { INIT_UNION(SOME_CONSTANT), /* 应生成:{.literal = 10} */ INIT_UNION(SOME_VARIABLE) /* 应生成:{.pv_variable = &some_variable} */ };
实现方案
利用GCC的两个内置扩展__builtin_constant_p()和__builtin_choose_expr(),结合C99复合字面量特性,可实现需求:
#define INIT_UNION(val) \ __builtin_choose_expr( \ __builtin_constant_p(val), \ (foo_t){.literal = (val)}, \ (foo_t){.pv_variable = &(val)} \ )
原理说明
__builtin_constant_p(val):编译期判断val是否为常量表达式,是则返回1,否则返回0。__builtin_choose_expr(cond, expr1, expr2):编译期根据cond结果选择表达式,若cond为真则展开为expr1,否则展开为expr2,未选中的分支不会被编译。- 复合字面量
(foo_t){...}:直接构造并返回foo_t类型的联合体实例,符合数组初始化语法要求。
验证代码
将上述宏代入目标代码,编译后会生成预期的初始化逻辑:
#define INIT_UNION(val) \ __builtin_choose_expr( \ __builtin_constant_p(val), \ (foo_t){.literal = (val)}, \ (foo_t){.pv_variable = &(val)} \ ) #define SOME_VARIABLE some_variable #define SOME_CONSTANT 10 int some_variable = 20; typedef union { void* pv_variable; int literal; } foo_t; foo_t test_array[] = { INIT_UNION(SOME_CONSTANT), /* 实际展开为:(foo_t){.literal = 10} */ INIT_UNION(SOME_VARIABLE) /* 实际展开为:(foo_t){.pv_variable = &some_variable} */ };
注意事项
- 该方案依赖GCC扩展,无法在标准C或非GCC兼容编译器中使用。
- 若传入的
val是变量,必须确保其有明确的内存地址(不能是临时值或寄存器变量)。
内容的提问来源于stack exchange,提问作者user1806687
相关产品推荐
相关产品推荐

