C语言得到变参数量的宏,0参数不会错误返回1,gcc和msvc都测试通过
参考 https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments 我原先用的是: #define _expand(x) x #define _numargs(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, N, ...) N #define numargs(...) _expand(_numargs(_, ##__VA_ARGS__, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) msvc必须要用_expand套一下,原因据说是参数展开时机问题,但零参数会得到错误结果1,gcc有另外的问题,就是不能使用比如-std=c99 -std=c23,否则零参数也是1,原因是##是gcc扩展,参见https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html,而标准c直到c23才加入__VA_OPT__,有意思的是msvc也支持##。 高赞那个用(sizeof((int[]){__VA_ARGS__})/sizeof(int))的,首先msvc必须高版本,且会报C4047类型不匹配警告,而gcc则是错误无法编译。 只有下面6赞的回答是完美的,我稍微调整了下,以适配个人风格: #define _numargs_call(__arg_0, __arg_1) __arg_0 __arg_1 #define _numargs_select(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, __arg_0, ...) __arg_0 #define numargs(...) _numargs_call(_numargs_select, (_, ##__VA_ARGS__, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) msvc现在是用_numargs_call套一下,零参数不会出问题了,甚至古老的vs2007/wdk7.1也正常。 测试代码: int main() { printf("numargs = %d\n", numargs()); printf("numargs = %d\n", numargs(1)); printf("numargs = %d\n", numargs(1, 3.14)); printf("numargs = %d\n", numargs(1, 3.14, "hello")); return EXIT_SUCCESS; } 执行cl test.c && test.exe或gcc -o test.exe test .c && ./test.exe,结果都是: numargs = 0 numargs = 1 numargs = 2 numargs = 3

参考 https://stackoverflow.com/questions/2124339/c-preprocessor-va-args-number-of-arguments
我原先用的是:
#define _expand(x) x
#define _numargs(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, N, ...) N
#define numargs(...) _expand(_numargs(_, ##__VA_ARGS__, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
msvc必须要用_expand
套一下,原因据说是参数展开时机问题,但零参数会得到错误结果1,gcc有另外的问题,就是不能使用比如-std=c99
-std=c23
,否则零参数也是1,原因是##
是gcc扩展,参见https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html,而标准c直到c23才加入__VA_OPT__
,有意思的是msvc也支持##
。
高赞那个用(sizeof((int[]){__VA_ARGS__})/sizeof(int))
的,首先msvc必须高版本,且会报C4047类型不匹配警告,而gcc则是错误无法编译。
只有下面6赞的回答是完美的,我稍微调整了下,以适配个人风格:
#define _numargs_call(__arg_0, __arg_1) __arg_0 __arg_1
#define _numargs_select(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, __arg_0, ...) __arg_0
#define numargs(...) _numargs_call(_numargs_select, (_, ##__VA_ARGS__, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
msvc现在是用_numargs_call
套一下,零参数不会出问题了,甚至古老的vs2007/wdk7.1也正常。
测试代码:
int main() {
printf("numargs = %d\n", numargs());
printf("numargs = %d\n", numargs(1));
printf("numargs = %d\n", numargs(1, 3.14));
printf("numargs = %d\n", numargs(1, 3.14, "hello"));
return EXIT_SUCCESS;
}
执行cl test.c && test.exe
或gcc -o test.exe test
,结果都是:
.c && ./test.exe
numargs = 0
numargs = 1
numargs = 2
numargs = 3