【问题标题】:Simulating scope in C macros在 C 宏中模拟作用域
【发布时间】:2013-12-25 04:57:59
【问题描述】:

出于调试目的,我有以下宏来打印整数数组的内容:

#define PRINT_ARRAY(ary, num)        \
    int ai = 0;                      \
    printf("{");                     \
    for(ai=0; ai < num; ++ai) {      \
        printf("%d", ary[ai]);       \
        if(ai < num-1) printf(", "); \
    }                                \
    printf("}\n");

我遇到的问题是,当我多次使用它时,一些编译器抱怨我正在重新定义ai

有没有办法让每次调用宏的标识符都不同?我可以想出一个名称冲突更改非常低的命名方案,但我想让它自动进行。

我知道我可以使用函数,但我仍然很好奇,因为我想知道是否有办法使用宏来做到这一点。

【问题讨论】:

    标签: c macros scope


    【解决方案1】:

    你可以把它放到它自己的范围内,例如用{}包围它

    像这样:

    #define PRINT_ARRAY(ary, num)        \
    {                                \
        int ai = 0;                      \
        printf("{");                     \
        for(ai=0; ai < (num); ++ai) {      \
            printf("%d", ary[ai]);       \
            if(ai < (num)-1) printf(", "); \
        }                                \
        printf("}\n");                   \
    }
    

    我还在 num 参数周围添加了括号,因此您可以使用复杂的表达式而不会产生奇怪的副作用。

    WRT 到你的标识符命名:

    您可以使用宏扩展来使用参数更改名称,但由于我知道的所有 c 预处理器中都没有计数器或循环构造,我认为不可能在每个用户之后自动更改标识符。另一种方法是让宏每次都重新定义自己,但这也是不可能的。

    编辑:

    正如已经指出的那样(感谢 Aaron McDaid,还可以查看他发布的链接:https://stackoverflow.com/a/1067238/146041),您应该在代码周围使用 do { } while(0) 构造,这样您的宏将变为:

    #define PRINT_ARRAY(ary, num)        \
    do {                                \
        int ai = 0;                      \
        printf("{");                     \
        for(ai=0; ai < (num); ++ai) {      \
            printf("%d", ary[ai]);       \
            if(ai < (num)-1) printf(", "); \
        }                                \
        printf("}\n");                   \
    } while(0)
    

    【讨论】:

    【解决方案2】:

    如果您的 C 符合 C99,请将 ai 的声明放在 for 循环的标题中。您还应该在代码周围加上do / while(0)

    #define PRINT_ARRAY(ary, num)        \
        do {printf("{");                     \
        for(int ai=0; ai < num; ++ai) {      \
            printf("%d", ary[ai]);       \
            if(ai < num-1) printf(", "); \
        }                                \
        printf("}\n"); } while(0)
    

    这样它就可以在控制结构之后使用而不用花括号括起来。

    【讨论】:

    • 删除结尾的;
    • 在任何一种情况下,它都应该放在do {...} while(0) 中。例如,if(...) 之后的第一个宏将不正确。
    【解决方案3】:

    为什么不使用经典的 do-while 技巧?例如:

    #define FOO(EXPR) \
      do { \
        (EXPR); \
      } while(0)
    

    【讨论】:

    猜你喜欢
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 2017-05-08
    相关资源
    最近更新 更多