LOG实现中,宏的一点使用技巧

这里主要总结几个使用技巧:

 

1、无固定个数参数

2、##和#

3、在无固定个数参数后面再添加一个参数

示例:

我们经常会在函数中做一些判断,进而以此为依据进行后续的执行。假定要求在判断的时候,如果条件是false,那么记录下出错信息并跳转到到出错处理。

假定在某函数Test中,如果条件满足,那么输出信息并直接goto到出错处理, 一般的程序处理如下:

void Test (void )

{

     int a,b,c;

     .....

     if((a>b)&&(a<c) //随便定义一个条件

     {    

             printf("Test err, a>b && a<c, a = %d, b = %d, c = %d/n"); 

             goto FUNC_EXIT;

     ....

     return;

 FUNC_EXIT:

     ....

}

通过宏,我们可以用下面的方式来实现该程序段功能;虽然在此看起来下面的实现繁琐而无味,但是在大型项目中,对于程序模块化、统一风格等等还是很有帮助的:

首先,准备一个无固定个数参数的函数,用于记录信息:

bool Log( bool condition, const char* file_name, const char* func_name, int line_num, const char* format, ...)

{

     if (condition) return true;

     printf(" file: %s, func: %s, line %d ", __FILE__, __FUNCTION__, __LINE__);

     va_list args;
     va_start( args, format );

     printf(format, args);     

     va_end( args);

     return false;

}

方法<一>

接下来,定义一个宏:

#define LOG_ASSERT(x)  {if ((Log x) ==false) goto FUNC_EXIT;}

这可能有点奇怪,就一个参数阿,怎么用呢?下面就来分解:

void Test (void )

{

     int a,b,c;

     .....

     LOG_ASSERT( ( (a>b)&&(a<c), __FILE__, __FUNCTION__, __LINE__, "ERR, condition is false, a = %d, b = %d, c = %d/n", a, b, c) );  

     .....

     return;

 FUNC_EXIT:

     ....

}

没看出来?注意看LOG_ASSERT后面,要多一层括号才可以!

方法<二>

#define LOG_ASSERT_2(con, file, func, line, format, arg...)  /

     { if (Log(con, file, func, line, format, ##g)==false) goto FUNC_EXIT;}

注意调用宏的时候,跟方法<一>中是不同的,这里我们会觉得比较熟悉:

LOG_ASSERT_2( (a>b)&&(a<c), __FILE__, __FUNCTION__, __LINE__, "ERR, condition is false, a= %d, b = %d, c = %d/n");

方法<二>扩展

有时候,对这种实现我们还是不满意,希望把判断的条件记录在输出信息上,应当怎么做呢?

用方法<一>中的实现无法扩展,只能扩展方法<二>中的宏。原因在于,在方法<一>的宏调用中,多个参数被内层的括号括起来了,表示一个整体,所以在宏定义中,也无法分离出各个参数,也就无法进行扩展了。

假设将判断条件输出在已有的输出之后,看看进一步实现后的宏:

#define LOG_ASSERT_3(con, file, func, line, format, arg...) /

     {    if (LOG_ASSERT_2(con, file, func, line, format##", %s /n", ##arg, #a) == false) /

              goto FUNC_EXIT; /

     }

我们来理解一下:

1、format##", %s "

表示在已有的字符串后面再添加一个字符串,这里表示要添加一个输出格式控制。

2、##arg

表示无固定个数的参数。

3、#a

表示将条件表达式转换成字符串。

这样,就在无固定个数参数的末尾又添加了一个参数!

应用

看一下扩展后的宏的调用方式以及调用结果:

调用方式:

LOG_ASSERT_3( (a>b)&&(a<c), __FILE__, __FUNCTION__, __LINE__, "ERR: a = %d, b = %d, c = %d", a, b,c );

假如 a = 20, b = 10, c = 30,那么条件为false,输出结果就是:

cmd> file: test.c, func: Test, line: 102, ERR: a = 20, b = 10, c = 30, (a>b)&&(a<c)

对于##和#的使用方法,网上很多,search一下就清楚了。

OVER

猜你喜欢

转载自blog.csdn.net/zwinger/article/details/4331610