在C / C ++中检查NULL指针

时间:2010-09-29 20:40:27

标签: c++ c coding-style code-formatting

在最近的代码审查中,贡献者试图强制执行对指针的所有NULL检查,方法如下:

int * some_ptr;
// ...
if (some_ptr == NULL)
{
    // Handle null-pointer error
}
else
{
    // Proceed
}

而不是

int * some_ptr;
// ...
if (some_ptr)
{
    // Proceed
}
else
{
    // Handle null-pointer error
}

我同意他的方式更明确,因为它明确地说“确保这个指针不是NULL”,但我会反驳说,任何正在研究这段代码的人都会明白使用指针if语句中的变量隐式检查NULL。另外我觉得第二种方法引入类似错误的可能性较小:

if (some_ptr = NULL)

这对于查找和调试来说只是一种绝对的痛苦。

您更喜欢哪种方式?为什么?

15 个答案:

答案 0 :(得分:182)

根据我的经验,首选if (ptr)if (!ptr)形式的测试。它们不依赖于符号NULL的定义。他们没有暴露意外分配的机会。它们清晰简洁。

编辑:正如SoapBox在评论中指出的那样,它们与诸如auto_ptr之类的C ++类兼容,这些类是充当指针并提供到{{1}的转换的对象准确地启用这个成语。对于这些对象,与bool的显式比较必须调用转换为指针,这可能具有其他语义副作用,或者比NULL转换所暗示的简单存在检查更昂贵。

我偏爱代码,说明没有不需要的文本意味着什么。 boolif (ptr != NULL)具有相同的含义,但代价是多余的特异性。下一个合乎逻辑的事情是写if (ptr),这就是疯狂。 C语言很清楚,if ((ptr != NULL) == TRUE)if等测试的布尔值具有非零值的特定含义为真,零为假。冗余并没有让它更清晰。

答案 1 :(得分:50)

if (foo)足够清楚了。使用它。

答案 2 :(得分:24)

我将从这开始:一致性是王道,决定不如你的代码库中的一致性重要。

在C ++中

在C ++中将NULL定义为0或0L。

如果您已经阅读了 The C ++ Programming Language Bjarne Stroustrup suggests using 0 explicitly to avoid the NULL macro when doing assignment,我不确定他是否对比较做了同样的事情,因为我读了这本书已经有一段时间了,我想他只是做了if(some_ptr)没有明确的比较,但我对此很模糊。

原因是NULL宏具有欺骗性(几乎所有宏都是),它实际上是0文字,而不是名称所暗示的唯一类型。避免使用宏是C ++中的一般指导原则之一。另一方面,0看起来像一个整数,并且在与指针比较或分配时不是。我个人可以去任何一种方式,但通常我会跳过明确的比较(虽然有些人不喜欢这个,这可能就是为什么你有一个贡献者提出改变的原因)。

无论个人感受如何,这都是最不邪恶的选择,因为没有一种正确的方法。

这很清楚,也是一个常见的习惯用语,我更喜欢它,在比较过程中没有意外分配值的可能性,并且读得很清楚:

if(some_ptr){;}

如果你知道some_ptr是一个指针类型,但它看起来像一个整数比较,这很清楚:

if(some_ptr != 0){;}

这很清楚,在一般情况下它是有道理的......但它是一个漏洞的抽象,NULL实际上是0字面的,最终可能很容易被滥用:

if(some_ptr != NULL){;}

C ++ 0x有nullptr,现在它是首选方法,因为它明确而准确,只需注意意外分配:

if(some_ptr != nullptr){;}

在你能够迁移到C ++ 0x之前,我认为浪费时间来担心你使用哪种方法,它们都不足以解释为什么会发明nullptr(以及出现的泛型编程问题)完美的转发。)最重要的是保持一致性。

在C

C是一个不同的野兽。

在C中,NULL可以定义为0或((void *)0),C99允许实现定义的空指针常量。所以它实际上归结为实现的NULL定义,你必须在标准库中检查它。

宏是非常常见的,一般来说,它们用于弥补语言和其他方面的泛型编程支持的不足。语言更简单,对预处理器的依赖更为常见。

从这个角度来看,我可能建议在C中使用NULL宏定义。

答案 3 :(得分:19)

我使用if (ptr),但这完全不值得争论。

我喜欢自己的方式,因为它很简洁,但有些人说== NULL使阅读更容易,更明确。我看到他们来自哪里,我只是不同意额外的东西让它变得更容易。 (我讨厌宏观,所以我有偏见。)由你决定。

我不同意你的论点。如果您没有收到有条件的分配警告,则需要提高警告级别。就那么简单。 (为了所有善的爱,不要转换它们。)

注意在C ++ 0x中,我们可以if (ptr == nullptr),这对我来说 读得更好。 (再一次,我讨厌宏。但是nullptr很好。)我仍然会if (ptr),只是因为它是我习惯的。

答案 4 :(得分:9)

坦率地说,我不明白为什么这很重要。任何一个都很清楚,任何适度使用C或C ++的人都应该理解这两者。但有一条评论:

如果您计划识别错误而不继续执行该函数(即,您将抛出异常或立即返回错误代码),您应该将其作为保护条款:

int f(void* p)
{
    if (!p) { return -1; }

    // p is not null
    return 0;
}

这样,您就可以避免使用“箭头代码”。

答案 5 :(得分:7)

我个人总是使用if (ptr == NULL),因为它使我的意图明确,但此时这只是一种习惯。

使用=代替==将被具有正确警告设置的任何合格编译器捕获。

重点是为您的团队选择一致的风格并坚持下去。无论你走哪条路,你最终会习惯它,并且欢迎在使用其他人的代码时失去摩擦力。

答案 6 :(得分:7)

还有一点支持foo == NULL练习: 如果fooint *bool *,则if (foo)检查可能会被读者意外解释为测试指针对象的值,即为{ {1}}。这里的if (*foo)比较提醒我们,我们正在讨论指针。

但我认为一个好的命名惯例使这个论点没有实际意义。

答案 7 :(得分:4)

实际上,我使用两种变体。

在某些情况下,您首先检查指针的有效性,如果它是NULL,您只需返回/退出函数。 (我知道这可以导致讨论“如果一个函数只有一个退出点”)

大多数情况下,检查指针,然后执行所需操作,然后解决错误情况。结果可能是带有多个if的丑陋x次缩进代码。

答案 8 :(得分:4)

The C Programming Language (K& R)会检查null == ptr以避免意外分配。

答案 9 :(得分:3)

如果样式和格式将成为您评论的一部分,那么应该有一个商定的风格指南来衡量。如果有,请按照样式指南说。如果没有,那么这些细节应该在写完时留下。这是浪费时间和精力,并且分散了代码审查真正应该发现的内容。说真的,如果没有风格指南,我会尽量不改变这样的代码,即使它没有使用我喜欢的惯例。

并不重要,但我的个人偏好是if (ptr)。对我来说,这个含义比if (ptr == NULL)更明显。

也许他试图说在快乐路径之前处理错误状况会更好?在那种情况下,我仍然不同意审稿人。我不知道有一个公认的惯例,但在我看来,最“正常”的条件应该在任何if语句中排在第一位。这样我就可以更少地去弄清楚功能是什么以及它是如何工作的。

例外情况是,如果错误导致我从函数中保释,或者我可以在继续之前从中恢复。在这些情况下,我会先处理错误:

if (error_condition)
  bail_or_fix();
  return if not fixed;

// If I'm still here, I'm on the happy path

通过预先处理异常情况,我可以照顾它,然后忘记它。但是如果我不能通过预先处理它来回到快乐的道路上,那么它应该在主要案例之后处理,因为它使代码更容易理解。在我看来。

但如果它不是风格指南,那么这只是我的意见,你的意见同样有效。标准化或不标准化。不要让审稿人伪标准化只是因为他有意见。

答案 10 :(得分:1)

我使用的大多数编译器至少会警告if赋值而没有进一步的语法糖,所以我不买这个论点。也就是说,我既专业又使用,也没有偏好。在我看来,== NULL显然更清晰。

答案 11 :(得分:1)

我认为这很清楚:

if( !some_ptr )
{
  // handle null-pointer error
}
else
{
  // proceed
}

将其读作“如果没有指针......”

此外,它简洁明了,没有意外分配的危险。

答案 12 :(得分:1)

这是两种语言的基础之一,指针评估为可用作控件表达式的类型和值,C ++中为bool,C中为int。只需使用它。 / p>

答案 13 :(得分:1)

  • 指针不是布尔值
  • 当您意外编写if (foo = bar)时,现代C / C ++编译器会发出警告。

因此我更喜欢

if (foo == NULL)
{
    // null case
}
else
{
    // non null case
}

if (foo != NULL)
{
    // non null case
}
else
{
    // null case
}

但是,如果我正在编写一套风格指南,我就不会在其中加入这样的内容,我会提出类似的内容:

  

确保对指针进行空检查。

答案 14 :(得分:1)

我非常喜欢C / C ++不会在ifforwhile语句中检查布尔条件中的类型。我总是使用以下内容:

if (ptr)

if (!ptr)

即使是转换为bool的整数或其他类型:

while(i--)
{
    // Something to do i times
}

while(cin >> a >> b)
{
    // Do something while you've input
}

这种风格的编码对我来说更具可读性和清晰度。只是我个人的意见。

最近,在使用OKI 431微控制器时,我注意到以下内容:

unsigned char chx;

if (chx) // ...

更有效
if (chx == 1) // ...

因为在以后的情况下,编译器必须将chx的值与1进行比较。其中chx只是一个真/假标志。