可变参数宏的原理及作用

来源:互联网 发布:js获取所有input的值 编辑:程序博客网 时间:2024/05/29 04:43

有什么作用呢?


主要是为了方便管理软件中的打印信息。我们在写代码或者修改bug时通常会将一些重要参数打印出来,方便我们debug,但是软件发行的时候通常我们不希望有这些打印,可变参数宏就可以在这里大显身手,当然也可以用分级控制(ERR、INFO/ WARNING  DEBUG)的方式来管理,实现起来也不麻烦,只要在这个宏中添加判断语句就可以。

但是一般我们调试问题,不会把所有打印都打开,因为工程具有一定规模的时候,打印非常多;通常我们只打开某个文件或者模块的打印,这时可以再对应模块中添加变了或者宏来控制打印。


常用的有2种方式:

#define DEBUG_PRINT(fmt,args...) do{printf(fmt"\r", ##args);}while(0)

#define DEBUG_PRINT(fmt, ...) do {printf(fmt"\r",  ##__VA_ARGS__);}while(0)

效果一样的, 下面就来分析一下这个原理:


1. 首先我们需要知道,可变参数宏是在C99标准中才实现的,以前没定义这个 __VA_ARGS__宏,这个宏就代表可变参数列表,在GCC中  也支持args...这种写法。  

2. 关于do {...}while(0) 的用处多多,其中一个就是防止宏展开后,代码出问题。

例如, if(true) PRINTF   如果这时printf中含有2两以上代码,那么就会导致只能执行第一条。

3. ##  这个符号在宏定义中的作用是连接字符串,会忽略前后的空格, 如  A ## B   宏展开后为  AB

4. fmt "\r"   这里\r  是为了兼容windows下换行符。

fmt 就是前面的第一个参数 ,是一个字符串里面可以包含格式控制符, 这里宏展开后 fmt 会直接展开成printf的第一个参数。然后在printf函数中这个字符串和“\r”会自动连接成一个字符串。(这个字符串连接功能的具体实现不知道是不是在printf函数中


5. 关于宏展开我们可以再编译时指定  -E参数 就可以查看到宏展开后的代码。


如: gcc -E input.c  -o ouput.i

查看ouput.i 就可以发现宏展开后的是什么样子


举个例子:

/**********************************sum.c********************************************/


#include <stdio.h>


#ifdef DEBUG

#define DEBUG_PRINT(fmt,args...) do{printf(fmt"\r", ##args);}while(0)

#else

#define DEBUG_PRINT(fmt,args...) do{/*printf(fmt"\r", ##args)*/;}while(0)

#endif

int sum(int a, int b);

int main()

{

int result = 0;

result = sum(1, 2);

printf("result = %d\n", result);

return 0;

}


int sum(int a, int b)

{

DEBUG_PRINT("a = %d, b = %d\n", a, b);

return a+b;

}


/**********************************end********************************************/

当这个文件有几百行几千行的时候里面可以有很多打印信息,我们可以通过DEBUG宏来控制打印信息是否显示出来。

这样当关闭DEBUG宏时也不会有警告信息。

0 0
原创粉丝点击