C/C++ 使用宏在编译期计算可变参数个数

参考https://groups.google.com/forum/#!forum/comp.std.c/d-6Mj5Lko_s

同时参考了cppformat源代码

C++是不提倡可变参数,理由不说了。但是类似printf的函数族使用起来确实很方便,我在查找printf的替代方案时无意间看到的。感慨下,微软的CString::Format确实很好用

cppformat提供类似printf的功能,但是又是类型安全的,其核心是利用C++强大的模版功能。在实现上,cppformat实现了在编译期计算可变参数个数,原理就是https://groups.google.com/forum/#!forum/comp.std.c/d-6Mj5Lko_s里面讨论的

为简便起见,这里只以最多三个可变参数做讨论

#define   ARG_N(a1,a2,a3,N,...)  N

这个宏的作用是,截取并返回参数列表的第四个参数

#define  ARG_N_HELPER(...)  ARG_N(__VA_ARGS__)

辅助宏,为使结果计算正确

#define  COUNT_ARG(...)  ARG_N_HELPER(__VA_ARGS__,3,2,1,0)

计算可变参数个数宏,可变参数个数在   大于0,小于等于3   内范围内计算正确

例如:

COUNT_ARG(x)     ->  1
COUNT_ARG(x,y)   ->  2
COUNT_ARG(x,y,z) ->  3

以COUNT_ARG(x,y)为例,示意计算过程
COUNT_ARG(x,y)
-> ARG_N_HELPER(X,Y,3,2,1,0)
-> ARG_N(X,Y,3,2,1,0)  截取第四个参数  2

另外,在VC编译器上,编译可能会失败需要定义下面的宏

#define  ARG_T(t)  t
#define  ARG_N_HELPER(...)  ARG_T(ARG_N(__VA_ARGS__))

完整的宏如下

#define ARG_T(t)  t  //解决VC编译错误
#define ARG_N(a1,a2,a3,N,...)  N  //截取并返回第四个参数,这里限制了可变参数计算的范围[1,3]
#define ARG_N_HELPER(...)  ARG_T(ARG_N(__VA_ARGS__))   //辅助宏
#define COUNT_ARG(...)  ARG_N_HELPER(__VA_ARGS__,3,2,1,0)  //返回可变参数个数

示意代码

int main()
{
    int  argn = COUNT_ARG(1,2,3); //argn值为3
    return 0;
}
时间: 2024-12-20 14:35:06

C/C++ 使用宏在编译期计算可变参数个数的相关文章

Java编译期和运行期

Q.下面的代码片段中,行A和行B所标识的代码有什么区别呢? ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class ConstantFolding {       static final  int number1 = 5;       static final  int number2 = 6;       static int number3 = 5;       static int number4= 6;       

constexpr:编译期与运行期之间的神秘关键字

Scott Meyers在effective modern c++中提到"If there were an award for the most confusing new word in C++11, constexpr would probably win it." 由此可见,constexpr确实是比较难以让人理解.加之其在C++11和14中的标准略有不同,也加剧了这种难度. 参考几本经典教材(C++ primer, effective modern C++, a tour of

嵌入式C语言自我修养 12:有一种宏,叫可变参数宏

12.1 什么是可变参数宏 在上面的教程中,我们学会了变参函数的定义和使用,基本套路就是使用 va_list.va_start.va_end 等宏,去解析那些可变参数列表我们找到这些参数的存储地址后,就可以对这些参数进行处理了:要么自己动手,自己处理:要么继续调用其它函来处理. void print_num(int count, ...) { va_list args; va_start(args,count); for(int i = 0; i < count; i++) { printf(&qu

怎样写参数个数可变的宏 Debug宏 Log宏等

编译器内置宏: 先介绍几个编译器内置的宏定义,这些宏定义不仅可以帮助我们完成跨平台的源码编写,灵活使用也可以巧妙地帮我们输出非常有用的调试信息. ANSI C标准中有几个标准预定义宏(也是常用的): __LINE__:在源代码中插入当前源代码行号: __FILE__:在源文件中插入当前源文件名: __DATE__:在源文件中插入当前的编译日期 __TIME__:在源文件中插入当前编译时间: __STDC__:当要求程序严格遵循ANSI C标准时该标识被赋值为1: __cplusplus:当编写C

编写一个可变参数的C函数——头文件stdarg.h中宏va_start ,va_arg和va_end的应用

我们在C语言编程中会遇到一些参数个数可变的函数,例如printf()这个函数,它的定义是这样的:int printf( const char* format, ...);它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:printf("%d",i);printf("%s",s);printf("the number is %d ,string is:%s", i, s);究竟如何写可变参数的

可变参数宏__VA_ARGS__

在 GNU C 中,宏可以接受可变数目的参数,就象函数一样,例如: #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg) 用可变参数宏(variadic macros)传递可变参数表 你可能很熟悉在函数中使用可变参数表,如: void printf(const char* format, -); 直到最近,可变参数表还是只能应用在真正的函数中,不能使用在宏中. C99编译器标准终于改变了这种局面,它允许你可以定义可变参数宏(var

gnu printf可变参数宏

可变参数的宏 标准C只支持可变参数的函数,意味着函数的参数可以是不固定的 例如printf()函数的原型是int printf(const char *format [,argument]...) 而在GNU C中,宏也可以接受可变数目的参数,例如 #define pr_debug(fmt,arg...) printk(fmt,##arg) 这里arg表示其余的参数可以是零个或多个,这些参数以及参数之间的逗号构成arg的值,在宏扩展时替换arg ,例如 pr_debug("%s:%d"

gcc编译期打印宏的值

如果我们想知道一个宏的值应该怎么办? 要么在代码里加一句printf 要么在编译的时候gcc -E 第一种方法需要程序运行起来,颇为麻烦 第二种方法无法应付下面这些情况 比如宏的值等于sizeof(struct xxoo) 比如宏本身就是一个复杂的运算(((2U) << (((0+8)+8)+13)) | ((('W')) << (0+8)) | (((7)) << 0) | (((((sizeof(int) == sizeof(int[1]) && s

c++ 编译期与运行期总结

分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 转自:http://hi.baidu.com/zhaoyong200518/item/8516dc59a65be1968d12edff c++ 编译期与运行期总结 一 见识编译期的力量 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #in