此处引用csdn博客。链接如下、
http://blog.csdn.net/cp1300/article/details/7773239
http://blog.csdn.net/aobai219/article/details/6092292
我们在写程序的时候,总是或多或少会加入一些printf之类的语句用于输出调试信息,但是printf语句有个很不方便的地方就是当我们需要发布程序的时候要一条一条的把这些语句删除,而一旦需要再次调试的时候,这些语句又不得不一条条的加上,这给我们带来了很大的不便,浪费了我们很多的时间,也造成了调试的效率低下。所以,很多人会选择使用宏定义的方式来输出调试语句。
作者通过两文的阅读,总结如下,并添加了自己的观点。
引言
首先说明的是 printf("123! ""!""243");
语法正确,即输出等同printf("123! !243");
但是不似乎等同于printf("123! ","!","243");
正文
1
假如有如下定义
#define EEPROM_ERROR(fmt,...) printf("<<-EEPROM-ERROR->> "fmt" ",##__VA_ARGS__)
‘ … ’指可变参数。这类宏在被调用时,它(这里指‘ … ’)被表示成零个或多个符号,包括里面的逗号,一直到到右括弧结束为止。当被调用时,在宏体( macro body )中,那些符号序列集合将代替里面的 保留名__VA_ARGS__ 标识符。如果可变参数被忽略或为空,‘ ## ’操作将使预处理器( preprocessor )去除掉它前面的那个逗号,这样当宏定义调用没有变参时候,可以宏替换时候没有错误的逗号。
调用时候,使用如下语句
EEPROM_ERROR("a= %d,b=%d,c=%d",a,b,c);
这时替换结果为 "a= %d,b=%d,c=%d" 与 fmt
a,b,c 与 ... (即__VA_ARGS__)
替换后相当于printf("<<-EEPROM-ERROR->> ""a= %d,b=%d,c=%d"" ",a,b,c);
2
假如有如下定义
#define EEPROM_INFO(fmt,arg...) printf("<<-EEPROM-INFO->> "fmt" ",##arg)
调用方法与1相同。不同的是,去掉了保留名__VA_ARGS__
3
为了使printf作为的调试信息更具体,将以上的调试方案更进一步
3.1
ANSI C标准中有几个标准预定义宏(也是常用的):
__LINE__:在源代码中插入当前源代码行号;
__FILE__:在源文件中插入当前源文件名;
3.2
在有些时候, 并没有输出回车(环境为,win10+stc串口助手+stm32f429)。需要使用0x0d,0x0a之类的输出回车。所以使用了 作为一个回车效果
3.3
有如下定义:
#define EEPROM_ERROR(fmt,arg...) printf(" <<-EEPROM-ERROR->> ""LIFE NAME:"__FILE__ " ""LINE:%d "fmt" ",__LINE__,##arg)
调用如下:
EEPROM_ERROR("answer is c= %d c=%d c= %d",d,d,d);//假设c变量为uint8_t类型,值为6,并假设使用在第49行调用
输出结果为下:
<<-EEPROM-ERROR->>
LIFE NAME:..Usermain.c
LINE:49
answer is c= 6 c=6 c= 6
4
为了可以打开和关闭调试信息,可以将宏定义修改为:
#define EEPROM_ERROR(fmt,arg...) //printf(" <<-EEPROM-ERROR->> ""LIFE NAME:"__FILE__ " ""LINE:%d "fmt" ",__LINE__,##arg)
这样子,在整个工程中的通过宏定义方案输出的调试信息全部消失。而不是去使用#ifdef之类的宏定义开关语句开关宏定义