C 使用宏检查空值

C 使用宏检查空值,c,macros,C,Macros,我的C代码包含许多函数,其中指向不同结构的指针作为参数,不应该是空指针。为了使代码更具可读性,我决定替换此代码: if(arg1==NULL || arg2==NULL || arg3==NULL...) { return SOME_ERROR; } 使用该宏: NULL_CHECK(arg1,arg2,...) 如果参数的数量未知,并且它们可以指向不同的结构,我应该如何编写它?(我在C99工作)在我看来,最容易维护的解决方案是编写多个单独的调用,而不是试图“巧妙地”处理它 例如,W

我的C代码包含许多函数,其中指向不同结构的指针作为参数,不应该是空指针。为了使代码更具可读性,我决定替换此代码:

if(arg1==NULL || arg2==NULL || arg3==NULL...) {
    return SOME_ERROR;
}
使用该宏:

NULL_CHECK(arg1,arg2,...)

如果参数的数量未知,并且它们可以指向不同的结构,我应该如何编写它?(我在C99工作)

在我看来,最容易维护的解决方案是编写多个单独的调用,而不是试图“巧妙地”处理它

例如,Win32程序员使用VERIFY宏,该宏在调试时运行断言(该宏确保从发布代码中剥离断言);看到这样开始的函数并不罕见:

int foo(void* arg1, char* str, int n)
{
    VERIFY( arg1 != NULL );
    VERIFY( str != NULL );
    VERIFY( n > 0 );

显然,您可以很容易地将这3行压缩为一行,但如果不这样做,宏效果最好。如果将它们放在单独的行中,则失败的断言将告诉您这三个条件中的哪一个未满足,而将它们全部放在同一个语句中只会告诉您某个条件已失败,让您找出其余的条件。

如果您决定使用宏,则我建议使用带有单个参数的宏:

#define NULL_CHECK(val)  if (val == NULL) return SOME_ERROR;
然后你可以写:

NULL_CHECK(s1.member1);
NULL_CHECK(p2->member2);
其优点之一是,您可以准确地合并错误报告或日志记录,以识别第一个这样的无效成员。对于单个复合条件,您只知道其中至少有一个是无效的,但不知道是哪一个


如果你必须处理变量的变量,那么你需要进行调查,这将在C和C++中工作。

< P>不是我认为在宏中隐藏<代码>返回< /C> >语句是个好主意,但是这样的宏可以写成:

#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)
#定义空检查(…)\
做{\
void*_p[]={{uuuu VA_ARGS}\
int_i\
对于(_i=0;_i

基本上,将varargs扩展为一个数组并在索引上循环。

+1;一般来说,编写更改语言语法的C宏不是一个好主意(这里,通过在宏定义中包含return语句)。使用这样的断言是一种更好的方法。这不仅是做一些非常简单的事情的一种不必要的复杂方法,而且比原始代码效率更低。我不熟悉变量参数列表宏,但我怀疑它们不是类型安全的?如果是这样的话,这段代码也比原来的代码危险得多。@Lundin说得清楚,我不是在提倡使用这段代码,但我发现(ab)使用预处理器枚举变量宏的参数是一种奇怪的方式(我认为这或多或少是OP试图弄明白的)。宏不是类型安全的,但生成的代码是类型安全的(当然,使用
void*
也可以是类型安全的)。就效率而言,我将遵循关于过早优化的老引述。我怀疑除了最极端的情况外,它是否会在所有情况下造成明显的影响。根据我的经验,大多数优化器不会执行循环展开,除非您特别要求,因为它可能导致程序大小的增加。