我有以下问题 - 给出可变数量的宏参数argX来创建一个字符串化参数列表#argX
示例:
LIST(A, B) -> "A", "B"
LIST(A, B, C) -> "A", "B", "C"
我正在使用Boost,因此对于每个参数数量使用辅助宏并将LIST(...)分派给适当的LIST_n(arg1,... argn),上面的宏并不太难实现。
当LIST的输入本身是宏时,问题就开始了。在这种情况下(如果我使用...和__VA_ARGS__),宏在它们被字符串化之前会被扩展,给出:
#define A 10
LIST(A, B) -> "10", "B"
我希望这可以使用Windows标头中定义的宏,并且大多数值都有宏(MB_OK,AF_INET,...),所以我得到的是一个字符串化数字列表。
当不使用__VA_ARGS__时,一切正常:
#define A 10
#define LIST_1(arg0) #arg0
LIST_1(A) -> "A"
我已经尝试了几个宏将__VA_ARGS__的扩展推迟到以后的时间(例如,直到LIST_1,没有可变参数),但没有任何效果。
这是否可以使用C预处理器实现?
答案 0 :(得分:1)
我很抱歉,但现在有办法在msvc上执行此操作。由于预处理器中存在经典错误(请参阅here和here),因此将__VA_ARGS__
视为单个参数。要将其分解为单独的参数,需要应用另一个扫描,然后将扩展宏。在C99预处理器上,您可以使用空占位符禁止__VA_ARGS__
的扩展:
/* This counts the number of args */
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)
/* p is an empty placeholder used to inhibit the expansion of __VA_ARGS__ */
#define STRINGIZE_ALL(p, ...) FIRST(NARGS(__VA_ARGS__), PRIMITIVE_STRINGIZE_ALL(p ## __VA_ARGS__,~,~,~,~,~,~,~,~))
#define PRIMITIVE_STRINGIZE_ALL(x1, x2, x3, x4, x5, x6, x7, x8, ...) #x1, #x2, #x3, #x4, #x5, #x6, #x7, #x8
/* Retrieve the first n arguments from __VA_ARGS__ */
#define FIRST(n, ...) CAT(FIRST_, n)(__VA_ARGS__,~,~,~,~,~,~,~,~)
#define FIRST_1(x1, ...) x1
#define FIRST_2(x1, x2, ...) x1, x2
#define FIRST_3(x1, x2, x3, ...) x1, x2, x3
#define FIRST_4(x1, x2, x3, x4, ...) x1, x2, x3, x4
#define FIRST_5(x1, x2, x3, x4, x5, ...) x1, x2, x3, x4, x5
#define FIRST_6(x1, x2, x3, x4, x5, x6, ...) x1, x2, x3, x4, x5, x6
#define FIRST_7(x1, x2, x3, x4, x5, x6, x7, ...) x1, x2, x3, x4, x5, x6, x7
#define FIRST_8(x1, x2, x3, x4, x5, x6, x7, x8, ...) x1, x2, x3, x4, x5, x6, x7, x8
#define A 10
STRINGIZE_ALL(, A, B)
这适用于gcc和clang 3.4或更高版本的最多8个参数。