You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于编译时判断初始化正确的联合体成员

根据常量/变量动态初始化联合体成员

需要实现一个宏,根据传入的表达式是编译时常量还是变量,初始化联合体的不同成员。已找到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)} \
    )

原理说明

  1. __builtin_constant_p(val):编译期判断val是否为常量表达式,是则返回1,否则返回0。
  2. __builtin_choose_expr(cond, expr1, expr2):编译期根据cond结果选择表达式,若cond为真则展开为expr1,否则展开为expr2,未选中的分支不会被编译。
  3. 复合字面量(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 20:15:47