常用的有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。 这里加##字符串式为了解决在__VA_ARGS__为空时,后面多出来一个逗号的问题。个人猜测, ##连接符会将逗号与字符串链接,发现字符串为空,因此就删除其中的逗号,因为__VA_ARGS__这个宏里面,本身就是有可能包含任意多个逗号来支持多个参数。
4. fmt "\r" 这里\r 是为了兼容windows下换行符。
fmt 就是前面的第一个参数 ,是一个字符串里面可以包含格式控制符, 这里宏展开后 fmt 会直接展开成printf的第一个参数。然后在printf函数中这个字符串和“\r”会自动连接成一个字符串。(这个字符串连接功能的具体实现不知道是不是在printf函数中)