当通过PP_ARG_N给PP_ARG_X传递的变参列表__VA_ARGS__代表的参数列表长度为 N 时,PP_ARG_X的参数 XX 将展开为 N,于是我们就得到了__VA_ARGS__变参列表的长度。 现在,我们再定义一个实用宏PP_VA_NAME: #define PP_VA_NAME(prefix,...) \PP_CAT2(prefix,PP_ARG_N(__VA_ARGS__))#define PP_...
第 一个宏中由于没有对变参起名,我们用默认的宏__VA_ARGS__来替代它。第二个宏中,我们显式地命名变参为args,那么我们在宏定义中就可以用 args来代指变参了。同C语言的stdcall一样,变参必须作为参数表的最有一项出现。当上面的宏中我们只能提供第一个参数templt时,C标准要 求我们必须写成: myprintf(templ...
在VC6.0下由于不支持Varadic Macro,只能使用变参函数列表模拟。 在宏实现方式的参数中会使用参数"ptInst",这个是固定的实例指针对象名称,采用变参函数实现的话由于进入了不同的scope,不能使用"ptInst"来获取相关信息,因此需要把相关信息存到全局变量中保存,然后调用自定义的变参函数接收变参列表。实际上只是一个文...
注意:PRINT_XN(n)宏用#运算符组合字符串,##运算符把记号组合成一个新的标识符。 3、变参宏:...和__VA_ARGS__ 一些函数(如printf())接受数量可变的参数。stdvar.h头文件提供了工具,让用户自定义带可变参数的函数。C99/C11也对宏提供了这样的工具。 通过把宏参数列表中最后的参数写成省略号(即,3个点...
标识符中的...代表可变参数,args表示可变参数的名字,__LINE__是编译器内置的宏定义,表示当前行号。对于以上宏定义,如果我们传入的可变参数为空,会造成fprintf参数中多了一个逗号从而报错,为了解决这个问题,使用##表示如果可变参数为空,预处理器将去除掉它前面的那个逗号。
C语言中使用va_list系列变参宏实现变参函数,此处va意为variable-argument(可变参数)。 x86平台VC6.0编译器中,stdarg.h头文件内变参宏定义如下: typedef char*va_list;// 把 n 圆整到 sizeof(int) 的倍数#define_INTSIZEOF(n)((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))// 初始化 ap 指针,...
这三个点用在宏中就是变参宏(Variadic Macros),默认名称为__VA_ARGS__。如: #define WriteLine(...) { printf(__VA_ARGS__); putchar('\n');} 再WriteLine("MoreWindows"); 考虑下printf()的返回值是表示输出的字节数。将上面宏改成:
1) va_start 宏 作用: 根据 A 取得可变参数表的首指针并赋值给 ap。 原理: 根据最后一个固定参数 A 的地址 + 第一个变参对 A 的偏移地址,然后赋值给 ap,这样 ap 就是可变参数表的首地址(函数传递的参数会从右向左依次入栈,并且 ARM 的栈为降栈,所以参数 A 的地址最低)。
变参宏:...和_ VA_ARGS _ 16.4 宏和函数的选择 16.5 文件包含:#include 头文件示例 使用头文件 16.6 其他指令 #undef指令 从C预处理器角度看已定义 条件编译 预定义宏 #line和#error #pragma 泛型选择(C11) 16.7 内联函数(C99) 16.8 _Noreturn函数(C11) ...
以上就是使用宏定义的三个常见的使用场景。当然,还有很多其他的使用场景和应用,如字符串化、连接符、变参宏等,这里就不一一介绍了。感兴趣的读者可以自行探索和学习。 最后,我们要注意一些使用宏定义时的注意事项和常见的错误: 注意事项一:在定义和使用宏时,要注意使用括号将其包裹起来,以避免与其他运算符混淆。否...