c语言系统默认宏__VA_ARGS__、__LINE__等用于高效Debug
来源:互联网 发布:淘宝新规则2016及处罚 编辑:程序博客网 时间:2024/06/15 22:08
对于涉及多文件较大规模的程序员而言,在不同地方设置printf()
用于查看代码运行进展以及查看距离故障点最近位置是很有用的,但是手动地在系统中插入一个个printf(...)
,最终版一个个删显然太蠢了。这里介绍一个成体系的Debug函数组。
#ifdef _DEBUG#define DEBUG(...) fprintf(stderr, __VA_ARGS__ ) #else#define DEBUG(format,...)#endif
这样在编译时cl /D _DEBUG...
便是启动这些printf()函数,不定义_DEBUG
便是取消Debug功能。但是这里面的__VA_ARGS__
又是些什么东西? __VA_ARGS__
可变参数宏,使用场景:#define PRINT_ERROR(…) fprintf(stderr, VA_ARGS)
在C89年代,可变参数stdarg机理依旧只能使用在函数中,如经典的 int printf(const char* format, ...);
直到C99才允许定义可变参数宏,如上面PRINT_ERROR(...)
中的 ...
代表着这是一个可以变化的参数表,使用保留名__VA_ARGS__
把参数传给宏函数。
对于GCC采用ANSI标准而言,其支持的方式更为直观: #define PRINT_ERROR(args...) fprintf(stderr, args)
即其支持为可变参数序列起一个名称,并在后续的宏函数中直接使用代替,而不是项上面那样一直使用__VA_ARGS__
这一系统默认的伪宏。
还有可以提供更为详细位置信息的其他宏吗?是的,看下面。
#include <stdarg.h>#include <stdio.h>#define DEBUG(...) printf(__VA_ARGS__)#define XNAME(n) x##n#define PXN(n) printf("x"#n" = %d", x##n) //这里面古怪的"#n"中的双引号并没有用\转义,其实是因为这个部分标记并非是给程序运行段查看的//这个"#n"是给编译器的预编译器看的,告诉它这部分内容是需要替换的宏参数,需要先进行宏参数转换操作//比如如下这个更夸张的操作方式更是表明了""囊括的的部分会先作为宏展开的部分进行参数解读//#define DEBUG(format,...) printf("File: "__FILE__", Line: %05d: "format"/n", __LINE__, ##__VA_ARGS__) int main(){ DEBUG("当前源代码函数名:__FUNCTION__ = %s \n", __FUNCTION__ ); DEBUG("当前源代码行数:__LINE__ = %d \n", __LINE__ ); DEBUG("当前源代码文件名:__FILE__ = %s \n", __FILE__ ); DEBUG("当前编译日期〔注意和当前系统日期区别开来〕:__DATE__==%s\n", __DATE__); DEBUG("当前编译时间〔注意和当前系统日期区别开来〕:__TIME__==%s\n", __TIME__); DEBUG("当前系统时间戳:__TIMESTAMP__==%s\n", __TIMESTAMP__); //DEBUG("当要求程序严格遵循ANSIC标准时该标识符被赋值为1:__STDC__==%d\n", __STDC__); DEBUG("当用C++编译程序编译时,标识符__cplusplus就会被定义:__cplusplus==%d\n", __cplusplus); int XNAME(1) = 12; PXN(1); return 0;}
这样便可以定义出最终版的Debug的组合函数
#define PRINT_ERROR(...) fprintf(stderr, __VA_ARGS__)#define MY_ASSERT(value) if(!(value)) { PRINT_ERROR("\"%s\" failed at %s:%d %s \n",\ #value,__FILE__,__LINE__,__FUNCTION__);}#define SHOW_LOCA() PRINT_ERROR(" current line_NO = %d \n", __LINE__ );static FILE* g_out_file = NULL; //甚至还可以定义Log登陆文件信息,配合如下函数实现信息保存static void InitLog( const char* file_name ){#ifdef BINDINGS_LOG MY_ASSERT( file_name ); if ( g_out_file == NULL ) { g_out_file = fopen( file_name, "w" ); } if ( g_out_file == NULL ) { printf( "Create %s failed\n", file_name ); } printf( "Bindings were written into %s, please check it for details.\n", file_name );#endif return ;}
阅读全文
0 0
- c语言系统默认宏__VA_ARGS__、__LINE__等用于高效Debug
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C语言 ## __VA_ARGS__ 宏
- C/C++语言宏的冷知识,内置宏,__FILE__,__LINE__,##, 可变参的宏...和__VA_ARGS__
- C/C++语言宏的冷知识,内置宏,__FILE__,__LINE__,##, 可变参的宏...和__VA_ARGS__
- C语言中__FILE__ 和__LINE__ 等宏的含义
- C语言预定义宏(__LINE__、__DATE__等)浅析
- java虚拟机运行时数据区简介
- lv扩容后resize2fs不生效的解决办法
- Effective C++ 02
- 1142: 二进制数的大小
- 主席树
- c语言系统默认宏__VA_ARGS__、__LINE__等用于高效Debug
- 在unity中实现方向盘UI的随着触摸转动和手指离开复位功能
- Java 虚拟机永久代的垃圾收集
- Servlet与Jsp的结合使用实现信息管理系统二
- Spring MVC 中重定向和转发
- Java 计算机图形学beizer生成以及升降阶
- springboot整合redis
- Spark算子[14]:top、takeOrdered 源码实例详解
- bashrc与profile理解