user-0 提问: 带参数的宏的问题

回复:
user: user-1
content: 理解和讨论之前请先学会如何观察！  VC编译选项加/EP /P（项目、属性、配置属性、C/C++、预处理器、预处理到文件：是，预处理取消显示行号：是），重新编译，查看宏展开后对应的.i文件。gcc加-E http://bbs.csdn.net/topics/391003898

user: user-2
content: 1、DDD的定义中 19,18,17,16,15,14,13,12,11,10, 这行后面少了个续行符\ 即，应该是 19,18,17,16,15,14,13,12,11,10,\  2、个人认为学习宏的最好方法就是用cpp或者gcc -E看宏展开后的结果:  $ cat main.c #define EXPAND(X) X #define AAA(...) EXPAND(BBB(__VA_ARGS__, DDD())) #define BBB(...) EXPAND(CCC(__VA_ARGS__))  #define CCC(\ _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 DDD()\ 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  EXPAND(hello)  $ cpp main.c # 1 "main.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 1 "<command-line>" 2 # 1 "main.c" # 23 "main.c" hello   3、如上，EXPAND比较简单，即参数是什么，原封不动的替换成什么；  DDD也比较简单， DDD() 展开后为 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  CCC需要至少64个参数，返回第64参数，  CCC( 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) 展开后为 0  CCC(a, b, c,\ 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) 展开后为 3  4、由上类似分析BBB和AAA可以得到LS的结论，AAA用于返回参数的个数，即 AAA(1) 展开后为 1  AAA(a, b) 展开后为 2  但AAA有一个bug和一个限制： bug是 AAA() 展开后为 1 限制是最多能有64个参数，多了就不是这个意思了。

user: user-3
content: http://velep.com/archives/581.html

user: user-4
content: CCC 计算第 64 个参数的值，而这个参数就是 DDD 生成的。 如果 AAA 本身带几个参数，那么 DDD 的参数就会后移。 所以 AAA 就是计算 __VA_ARGS__ 的参数个数。  但是你的 AAA 不能计算 AAA() 参数的个数。 因为 (__VA_ARGS__, DDD()) 的时候，添加了一个逗号，此时会认为有一个参数。 所以 AAA() 和 AAA(1) 的个数都是 1。 你需要添加一个判断，而且还要注意处理多重宏的问题。

user: user-1
content: Visual C++ Language Reference  Variadic Macros   Variadic macros are function-like macros that contain a variable number of arguments.  Remarks To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition, and the replacement identifier __VA_ARGS__ may be used in the definition to insert the extra arguments. __VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them.  The C Standard specifies that at least one argument must be passed to the ellipsis, to ensure that the macro does not resolve to an expression with a trailing comma. The Visual C++ implementation will suppress a trailing comma if no arguments are passed to the ellipsis.  Support for variadic macros was introduced in Visual C++ 2005.  Example   Copy Code  // variadic_macros.cpp #include <stdio.h> #define EMPTY  #define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); } #define CHECK2(x, ...) if ((x)) { printf(__VA_ARGS__); } #define CHECK3(...) { printf(__VA_ARGS__); } #define MACRO(s, ...) printf(s, __VA_ARGS__)  int main() {    CHECK1(0, "here %s %s %s", "are", "some", "varargs1(1)\n");    CHECK1(1, "here %s %s %s", "are", "some", "varargs1(2)\n");   // won't print     CHECK2(0, "here %s %s %s", "are", "some", "varargs2(3)\n");   // won't print    CHECK2(1, "here %s %s %s", "are", "some", "varargs2(4)\n");     // always invokes printf in the macro    CHECK3("here %s %s %s", "are", "some", "varargs3(5)\n");     MACRO("hello, world\n");    // MACRO("error\n", EMPTY);   would cause C2059 }     Copy Code  here are some varargs1(1) here are some varargs2(4) here are some varargs3(5) hello, world    See Also Concepts Macros (C/C++) Send feedback on this topic to Microsoft.