c - 让宏计算它的调用

标签 c macros c-preprocessor

我有一个巨大的 C 项目,其中包含一个读取和管理配置数据的模块。如果我必须添加一个新的配置参数,我将不得不编辑几个函数,例如作为伪代码:

void read_configuration(config *c) {
    read_param("p1", c->p1);
    read_param("p2", c->p2);
    read_param("p3", c->p3);
    /* ... */
}

void dump_configuration(config *c) {
    dump_param("p1", c->p1);
    dump_param("p2", c->p2);
    dump_param("p3", c->p3);
    /* ... */
}

有没有办法通过宏在编译时确保每个位置至少有相同数量的参数?我想制作 dump_param 某种宏来计算调用,然后添加类似的东西

#if nr_read != nr_dump
    #error "You forgot something, idiot!"
#endif

在模块的末尾。不过,我找不到让宏计算其调用次数的方法...

最佳答案

由于两个函数中的参数列表相同,如何分解那个并避免任何可能的不匹配?

使用 X 宏

#define X_CONFIG_PARAMS(config) \
    X("p1", (config).p1)        \
    X("p2", (config).p2)        \
    X("p3", (config).p3)

void read_configuration(config *c) {
#define X(name, param) read_param(name, &param);
    X_CONFIG_PARAMS(*c)
#undef X
}

void dump_configuration(config *c) {
#define X(name, param) dump_param(name, &param);
    X_CONFIG_PARAMS(*c)
#undef X
}

使用函数指针

void alter_config(config *c, void(*func)(char const *name, Param *param)) {
    func("p1", &c->p1);
    func("p2", &c->p2);
    func("p3", &c->p3);
}

void read_configuration(config *c) {
    alter_config(c, read_param);
}

void dump_configuration(config *c) {
    alter_config(c, dump_param);
}

使用数组和offsetof

struct param_info {
    char const *name;
    size_t config_offs;
};

param_info allParams[] = {
    {"p1", offsetof(config, p1)},
    {"p2", offsetof(config, p2)},
    {"p3", offsetof(config, p3)}
};

void read_configuration(config *c) {
    size_t paramCount = sizeof allParams / sizeof *allParams;
    for(size_t i = 0; i < paramCount; ++i) {
        Param *p = (Param*)((char*)config + allParams[i].config_offs);
        read_param(allParams[i].name, p);
    }
}

void dump_configuration(config *c) {
    size_t paramCount = sizeof allParams / sizeof *allParams;
    for(size_t i = 0; i < paramCount; ++i) {
        Param *p = (Param*)((char*)config + allParams[i].config_offs);
        dump_param(allParams[i].name, p);
    }
}

关于c - 让宏计算它的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31050784/

相关文章:

c++ - 使用 Arduino 编写一个简单的按钮 LED 电路

macros - 在 Clojure 中创建对象

c - 如何声明变量参数的数据类型?

c - __gc 方法用于 lua 中的 malloced 用户数据?

c - 在评估 C 表达式时,临时结果存储在哪里?

c# - 错误 "the action was blocked by organization policy ms office 2016"

C预处理器展开顺序

c - 相对于函数开头的 __LINE__ 宏的等价物

c - 通过 token 连接重复调用宏是未指定的行为吗?

c - 静态内存与堆内存?