c语言系统默认宏__VA_ARGS__、__LINE__等用于高效Debug

对于涉及多文件较大规模的程序员而言,在不同地方设置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 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值