这里主要总结几个使用技巧:
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