我的C代码包含许多函数,其中指向不同结构的指针作为参数,不应该是NULL指针。为了使我的代码更具可读性,我决定替换这段代码:
if(arg1==NULL || arg2==NULL || arg3==NULL...) {
return SOME_ERROR;
}
使用该宏:
NULL_CHECK(arg1,arg2,...)
如果args的数量未知且它们可以指向不同的结构,我应该如何编写它? (我在C99工作)
答案 0 :(得分:7)
IMO最易维护的解决方案是编写多个单独的调用,而不是试图让它“聪明”。
例如,Win32程序员使用一个VERIFY宏,它在调试时运行一个断言(宏确保从释放代码中删除断言);看到像这样开始的功能并不罕见:int foo(void* arg1, char* str, int n)
{
VERIFY( arg1 != NULL );
VERIFY( str != NULL );
VERIFY( n > 0 );
显然,你可以很容易地将这3行压缩成一行,但是当你不这样做时,宏效果最好。如果你将它们放在不同的行上,那么失败的断言会告诉你哪三个条件没有得到满足,而把它们全部放在同一个语句中只会告诉你某些事情已经失败,让你弄明白其余的。< / p>
答案 1 :(得分:1)
如果您决定使用宏,那么我建议使用一个带有一个参数的宏:
#define NULL_CHECK(val) if (val == NULL) return SOME_ERROR;
然后你可以写:
NULL_CHECK(s1.member1);
NULL_CHECK(p2->member2);
等。其中一个优点是您可以准确地合并错误报告或记录以识别第一个无效成员。使用单个复合条件,您只知道其中至少有一个是无效的,但不完全是哪一个。
如果你必须处理可变数量的参数,那么你需要调查Boost::Preprocessor
,它将在C和C ++中工作。
答案 2 :(得分:0)
并不是说我认为在宏中隐藏return
语句是个好主意,但是这样的宏可以写成:
#define NULL_CHECK(...) \
do { \
void *_p[] = { __VA_ARGS__ }; \
int _i; \
for (_i = 0; _i < sizeof(_p)/sizeof(*_p); _i++) { \
if (_p[_i] == NULL) { \
return SOME_ERROR; \
} \
} \
} while(0)
基本上,将varargs扩展为数组并循环索引。