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

如何定义C宏,根据传入变量的值生成变量名(令牌)?

这个需求刚好可以用C预处理器的**令牌拼接(##)**特性来实现,我给你两种不同场景下的实现方案,你可以根据实际需求选择:

基础实现:适用于参数为字面量的场景

如果你的n和f都是直接的字面量(比如0、1、data、status),可以用最简单的宏直接拼接令牌:

#define MEMBER(x, n, f) x->bar##n##_##f

用法示例

#include <stdint.h>

struct foo {
    uint32_t bar0_data;
    uint32_t bar0_status;
    uint32_t bar1_data;
    uint32_t bar1_status;
};

int main() {
    struct foo my_foo = {0};
    struct foo *p = &my_foo;

    // 等价于 p->bar0_data = 0xABCD;
    MEMBER(p, 0, data) = 0xABCD;
    // 等价于 uint32_t s = p->bar1_status;
    uint32_t s = MEMBER(p, 1, status);

    return 0;
}

通用实现:支持参数为宏的场景

如果n或f是通过宏定义的(比如#define BAR_INDEX 0),上面的基础宏会直接把宏名当作令牌拼接,导致错误。这时候需要加一层中间宏来先展开参数,再进行拼接:

// 中间宏:负责实际的令牌拼接
#define MEMBER_CONCAT(prefix, num, field) prefix##num##_##field
// 对外暴露的宏:先展开参数,再调用拼接宏
#define MEMBER(x, n, f) x->MEMBER_CONCAT(bar, n, f)

用法示例

#include <stdint.h>

#define BAR_INDEX 1
#define FIELD_STATUS status

struct foo {
    uint32_t bar0_data;
    uint32_t bar0_status;
    uint32_t bar1_data;
    uint32_t bar1_status;
};

int main() {
    struct foo my_foo = {0};
    struct foo *p = &my_foo;

    // 等价于 p->bar1_status = 0x1;
    MEMBER(p, BAR_INDEX, FIELD_STATUS) = 0x1;

    return 0;
}

为什么需要中间宏?

C预处理器有个规则:如果宏参数出现在##令牌旁边,会阻止该参数的预展开。通过中间宏MEMBER_CONCAT,我们让n和f先完成宏展开,再进行令牌拼接,这样就能正确处理参数是宏的情况。

内容的提问来源于stack exchange,提问作者seacoder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:31:48