【问题标题】:How to append to an array using a variadic macro?如何使用可变参数宏附加到数组?
【发布时间】:2020-07-04 15:53:44
【问题描述】:

我正在尝试通过使用宏来消除一堆样板代码。

这是有效的。我可以替换:

int do_register_script(struct context *L)
{
    method_type const _instance_methods[] = {
        {"new", __new},
        {"delete", __delete}
        {NULL, NULL}
    };
    register_type(L, script, _instance_methods, 0);
    return 1;
}

使用宏

#define do_register_type(name) \
    int do_register_ ## name(struct context *L) \
    { \
        method_type const _instance_methods[] = { \
            {"new", __new}, \
            {"delete", __delete}, \
            {NULL, NULL} \
        }; \
        register_type(L, name, _instance_methods, 0); \
        return 1; \
    }

像这样:

do_register_type(script);

太完美了!

但我也有一些看起来像这样的:

int do_register_rectangle(struct context *L)
{
    method_type const _instance_methods[] = {
        {"new", __new},
        {"delete", __delete},
        {"area", area},
        {"perimeter", perimeter}
        {NULL, NULL}
    };
    register_type(L, rectangle, _instance_methods, 0);
    return 1;
}

现在上面的宏不起作用了。

如何向宏添加另一个参数以支持此功能?

我使用的是 C,而不是 C++,所以没有模板。

更新:有时代码使用别名作为名称

        {"area", area},
        {"Area", area},
        {"perimeter", perimeter}
        {"Perimeter", perimeter}

【问题讨论】:

    标签: c macros variadic-macros


    【解决方案1】:

    你想要那个吗:

    #define do_register_type(name, ...) \
        int do_register_ ## name(struct context *L) \
        { \
            method_type const _instance_methods[] = { \
                {"new", __new}, \
                {"delete", __delete}, \
                __VA_ARGS__ __VA_OPT__(,) \
                {NULL, NULL} \
            }; \
            register_type(L, name, _instance_methods, 0); \
            return 1; \
        }
    
    do_register_type(script);
    
    do_register_type(script, {"area", area}, {"perimeter", perimeter});
    

    以前的代码在 m.c 中:

    pi@raspberrypi:~ $ gcc -E m.c
    # 1 "m.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 31 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 32 "<command-line>" 2
    # 1 "m.c"
    # 14 "m.c"
    int do_register_script(struct context *L) { method_type const _instance_methods[] = { {"new", __new}, {"delete", __delete}, {NULL, NULL} }; register_type(L, script, _instance_methods, 0); return 1; };
    
    int do_register_script(struct context *L) { method_type const _instance_methods[] = { {"new", __new}, {"delete", __delete}, {"area", area}, {"perimeter", perimeter} , {NULL, NULL} }; register_type(L, script, _instance_methods, 0); return 1; };
    pi@raspberrypi:~ $ 
    

    我注意到您不希望 areaperimeter 使用前缀 '__',这与 newdelete em> 但在其他情况下您可能想要它,因为它不可能自动扩展,我看到的唯一方法是明确给出要添加的代码

    【讨论】:

    • 无论如何要避免 do_register_type 中的尾随逗号?
    • 您的解决方案运行良好。很清楚(除了结尾的逗号)如何使用它。宏并不复杂。它支持别名。
    • @010110110101 我使用__VA_OPT__(,)将其删除了@查看我编辑的答案
    • 让 gcc 接受 __VA_OPT__(,) 有点麻烦。我试过 --std=c18 和其他一些方言。有什么建议吗?
    • 知道了。是我,不是编译器方言。
    【解决方案2】:

    在预处理器中循环列表通常需要生成样板宏,但您可以通过对列表使用有点奇怪的语法来避免这种情况:

    do_register_type(script, (area)(perimeter))
    

    以下是您遍历此类列表的方式:

    #define REG_LOOP(seq) REG_END(REG_LOOP_A seq)
    
    #define REG_END(...) REG_END_(__VA_ARGS__)
    #define REG_END_(...) __VA_ARGS__##_END
    
    #define REG_LOOP_A(func) REG_LOOP_BODY(func) REG_LOOP_B
    #define REG_LOOP_B(func) REG_LOOP_BODY(func) REG_LOOP_A
    #define REG_LOOP_A_END
    #define REG_LOOP_B_END
    
    #define REG_LOOP_BODY(func) {#func, func},
    

    REG_LOOP((foo)(bar)) 将扩展为 {"foo", foo}, {"bar", bar},

    然后你把这个宏添加到do_register_type:

    #define do_register_type(name, seq) \
        int do_register_ ## name(struct context *L) \
        { \
            method_type const _instance_methods[] = { \
                {"new", __new}, \
                {"delete", __delete}, \
                REG_LOOP(seq) \
                {NULL, NULL} \
            }; \
            register_type(L, name, _instance_methods, 0); \
            return 1; \
        }
    

    【讨论】:

    • 我正要警告你删除__,但你刚刚做了,我希望你的答案是OP想要的(而不是我的),这个问题不是很清楚......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多