尝试通过多个宏传递逗号时出错

时间:2014-09-03 14:17:23

标签: c compiler-errors c-preprocessor

我正在尝试通过多个级别的宏传递逗号,但预处理器不喜欢这样...

// This is just simplified, in reality I have some other variadic function which will
// stop upon encountering the -1 and APPEND_COMMA() may add more args (like `a, b,`)

#include <stdio.h>

#define MACRO_EX(val) printf("%d %d", val -1);

#define MACRO(val) MACRO_EX(val)

#define APPEND_COMMA(a) a,

int main() {
        MACRO(APPEND_COMMA(1));
        return 0;
}

究竟是什么导致编译失败?

test.c:10:8: error: too many arguments provided to function-like macro invocation
        MACRO(APPEND_COMMA(1));
              ^
test.c:7:26: note: expanded from macro 'APPEND_COMMA'
#define APPEND_COMMA(a) a,
                         ^
test.c:5:29: note: expanded from macro 'MACRO'
#define MACRO(val) MACRO_EX(val)
                            ^
test.c:3:9: note: macro 'MACRO_EX' defined here
#define MACRO_EX(val) printf("%d %d", val 0);
        ^
test.c:10:2: error: use of undeclared identifier 'MACRO_EX'
        MACRO(APPEND_COMMA(1));
        ^
test.c:5:20: note: expanded from macro 'MACRO'
#define MACRO(val) MACRO_EX(val)
                   ^
2 errors generated.

逗号似乎在被调用的宏中被扩展,因此调用MACRO_EX(a,),这不是我想要的。


我使用__VA_ARGS__找到了一些解决方法:

#define MACRO_EX(...) printf("%d %d", __VA_ARGS__ -1);

但是我真的更喜欢将逗号干净地通过所有宏传递到可变参数函数调用并使用干净命名的宏参数[就像我在原始代码中所预期的那样]。

有没有办法实现这个目标?

1 个答案:

答案 0 :(得分:1)

保证逗号的唯一方法是通过&#34;干净利落的&#34;通过宏参数将其包装在括号中:

#define APPEND_COMMA(a) (a,)

现在APPEND_COMMA的结果将始终是一个预处理器参数。

这个问题的一个明显问题是它产生printf("%d %d", (1,) -1);,它现在是有效的预处理器代码,但不再是有效的C代码。通过插入&#34;解压缩&#34;进入MACRO_EX的定义:

#define IDENTITY(...) __VA_ARGS__
#define MACRO_EX(val) printf("%d %d", IDENTITY val -1);
IDENTITY的重新扫描步骤中,

val将解包val的内容,假设MACRO_EX是带括号的参数列表。

如果val可能没有括号,因为它不包含逗号?答案是不要让它们出现。 可能包含逗号的参数应该始终被包装,因此可以在插入的最后一点安全地解包它们。需要根据宏是否预期单个令牌或列表来设计宏*。这是预处理器等同于静态类型约束:像MACRO这样的宏需要类型为list的参数,而不是类型为atom的类型(并且调用宏类似地需要用正确的类型签名编写) );在那些只需要一个参数的情况下,将它们传递给单个元素列表。

*技术上可以设计一个宏来测试它的参数是否带括号并在结果上分支,但是你会进入那里的黑暗魔法领域。为清晰起见,坚持使用固定类型。