我在代码中经常使用 X Macros()。该值来自仅将新数据添加到“X 列表”并且不修改任何其他代码。
X Macros() 最常见的用途是将错误文本与错误代码关联起来。当添加新的错误代码时,程序员必须记住添加代码和文本,通常是在不同的位置。 X 宏允许将新的错误数据添加到单个位置,并自动填充到任何需要的地方。
不幸的是,这些机制使用了大量的预编译器魔法,可能会使代码有点难以阅读(例如,字符串连接token1##token2
, 字符串创建#token
)。因此,我通常会在注释中解释 X 宏的作用。
这是使用错误/返回值的示例。所有新数据都会添加到“X_ERROR
” 列表。其他代码均无需修改。
/*
* X Macro() data list
* Format: Enum, Value, Text
*/
#define X_ERROR \
X(ERROR_NONE, 1, "Success") \
X(ERROR_SYNTAX, 5, "Invalid syntax") \
X(ERROR_RANGE, 8, "Out of range")
/*
* Build an array of error return values
* e.g. {0,5,8}
*/
static int ErrorVal[] =
{
#define X(Enum,Val,Text) Val,
X_ERROR
#undef X
};
/*
* Build an array of error enum names
* e.g. {"ERROR_NONE","ERROR_SYNTAX","ERROR_RANGE"}
*/
static char * ErrorEnum[] = {
#define X(Enum,Val,Text) #Enum,
X_ERROR
#undef X
};
/*
* Build an array of error strings
* e.g. {"Success","Invalid syntax","Out of range"}
*/
static char * ErrorText[] = {
#define X(Enum,Val,Text) Text,
X_ERROR
#undef X
};
/*
* Create an enumerated list of error indexes
* e.g. 0,1,2
*/
enum {
#define X(Enum,Val,Text) IDX_##Enum,
X_ERROR
#undef X
IDX_MAX /* Array size */
};
void showErrorInfo(void)
{
int i;
/*
* Access the values
*/
for (i=0; i<IDX_MAX; i++)
printf(" %s == %d [%s]\n", ErrorEnum[i], ErrorVal[i], ErrorText[i]);
}
您还可以使用 X Macros() 生成代码。例如,为了测试错误值是否“已知”,X 宏可以在 switch 语句中生成案例:
/*
* Test validity of an error value
* case ERROR_SUCCESS:
* case ERROR_SYNTAX:
* case ERROR_RANGE:
*/
switch(value)
{
#define X(Enum,Val,Text) case Val:
X_ERROR
#undef X
printf("Error %d is ok\n",value);
break;
default:
printf("Invalid error: %d\n",value);
break;
}