【问题标题】:What is the preferred way to check for a Null pointer in C++?在 C++ 中检查 Null 指针的首选方法是什么?
【发布时间】:2010-08-18 21:24:45
【问题描述】:

选项 A:

if (NULL == pSomethingColumn) // Yes, we use Yoda conditions
if (NULL != pSomethingColumn)

或者

if (pSomethingColumn)
if (!pSomethingColumn)

我也在寻找解释推理的参考资料。

我听一些人说,从技术上讲,NULL 不必定义为0,但是来吧!如果是这种情况,那么傻瓜(我们的应用程序)将以不同的方式崩溃 -2147483648

所以,如果NULL != 0,那我们就有大问题了。

请帮我解决毫无意义的语法辩论。我对这两种方式都不是特别执着;只是在寻找官方的方式。谢谢。

附:我们正在使用 Visual Studio C++ 编译器。

【问题讨论】:

  • 我很确定 NULL 在任何符合标准的编译器上都必须为 0。
  • @Hamish Grubijan:C++ 标准 4.10 “空指针常量是整数类型的整数常量表达式 (5.19) 右值,其计算结果为零。”和 18.1 “宏 NULL 是实现定义的 C++ 空指针常量”。同一页的脚注表明00LNULL 有效,但对(void *)0 无效。
  • 18.1/4:“宏 NULL 是本国际标准 (4.10) 中实现定义的 C++ 空指针常量”。但是 4.10 说“空指针常量是整数类型的整数常量表达式 (5.19) 右值,其计算结果为零。空指针常量可以转换为指针类型;结果是该类型的空指针值......”所以0 表示 NULL,但如果是 NULL,则不一定是按位 0。
  • 我觉得有必要指出 nullptr 只是 C++0x 中的另一个空指针常量。 0NULL(可能是也可能不是 nullptr_t 类型的东西,或者可能仍然是 0,取决于实现)不会消失。
  • 在 VS2005 及更高版本中不再需要 Yoda 条件,如果您错过其中一个等号,编译器会生成警告。

标签: c++ pointers null coding-style


【解决方案1】:

我认为零对应于假,非零对应于真是历史的偶然;我喜欢只为布尔表达式保留这些形式。但是,我在其他人的代码中看到该表单没有问题。

我的投票:

if (pSomethingColumn == NULL)

不,我从来没有因为忘记一个等号而被咬过。只是幸运,或者可能非常小心。

【讨论】:

  • 以这种方式阅读也更自然,如果您不小心在 if 语句中进行了赋值,所有现代编译器都会警告您(并且由于您(我们/我们所有人)将警告视为错误,因此不会编译):-)
  • @Martin York,您是否碰巧知道 Visual Studio 2010 C++ 编译器(非托管和托管)是否也会警告您?
  • @Hamish:是的,但仅限于警告级别 4。
  • 本周我了解到 gcc 4.3 不会发出警告,如果你反其道而行之:charArr[0] == ' '; 行不会产生警告。 (我们正在寻找“字符串始终为空”的错误)。
  • @IanH:是的,-Wall 我得到warning: statement with no effect. Clang 也会产生类似的警告。
【解决方案2】:

两者显然都不比另一个好。从技术角度来看,它们是等价的。指针上下文中的数字 0 并不意味着所有位都为零。它被定义为等同于用于表示空指针的任何位模式。 NULL 可以定义为0(void *) 0。任何一个定义都是语法上的,并且没有说明底层的位表示。

因此,就技术正确性而言,if (!p)if (p == NULL)if (p == 0) 相同。

问题是风格之一。像所有样式问题一样,您的第一个倾向应该是匹配流行的编码标准。做与代码库的其余部分相同的事情。如果没有通行标准,则取决于个人喜好,我们鼓励您与同行一起制定编码标准。

(我个人喜欢使用显式比较并为布尔值保留较短的语法,但我很乐意使用if (!p),这是其他人都在做的事情。)

【讨论】:

  • +1 建议跟随牛群。当您的代码将与群组共享时,这实际上是最重要的考虑因素。
  • 这是 C++,NULL 不能是 (void*)0 否则像 int *p = NULL; 这样的初始化是非法的。
  • 同样if (!p) 等价于if (p == 0) 而不是if (p != 0)
【解决方案3】:

在 C++ 中,NULL 在每个实现中都必须是一个空指针常量。 0 作为常量表达式始终是空指针常量(即,当转换为指针类型时,它会产生空指针值)。这些都不意味着任何给定指针类型的空指针值都必须由零或所有位为零的地址表示,但从应用程序开发人员的角度来看,这主要是学术性的。

要使用NULL,您应该在#include 一个定义它的标头,例如<cstddef>;你可以随时使用0

当转换为bool 时,空指针值始终转换为false;任何其他指针值始终转换为true

当用作一元 ! 的参数时,指针值会像上面一样转换为 bool,然后取反。

只要定义了NULL,这些都是等价的:

if (NULL == pSomethingColumn)
if (pSomethingColumn == NULL)
if (0 == pSomethingColumn)
if (pSomethingColumn == 0)
if (!pSomethingColumn)

这些都是等价的:

if (NULL != pSomethingColumn)
if (pSomethingColumn != NULL)
if (0 != pSomethingColumn)
if (pSomethingColumn != 0)
if (pSomethingColumn)

【讨论】:

    【解决方案4】:

    称我为古怪,但实际上我更喜欢每组中的一个。如果我要做一些特别需要指针存在的事情,我会使用if(ptr)。如果我要做一些特别要求指针为 NULL 的事情,我会使用if(NULL==ptr)。我想这源于这样一个理论,即更容易阅读未被否定的陈述。

    越多越好...if(!(0 != !ptr))

    【讨论】:

    • 废话,你刚刚发明了第三种方法。
    • 就我个人而言,我倾向于避免使用 if(!ptr),因为它不止一次发生了,我没有看到!在 ptr 之前,所以我猜错了测试。当我看到 if(!(0 != !ptr)) 我在 SVN 中进行搜索以了解作者的姓名,只是想知道这个精神病患者是否还在。 :-)
    • 顺便说一句,你总是可以做更多的心理不可读,你怎么看? : if(!(0 != !(ptr++)))
    【解决方案5】:

    您可能会找到支持其中任何一个的激烈论点的链接,但唯一的答案是:没关系。两者都是正确的,根据你的表现力标准,任何一个都可以被认为比另一个更具表现力。

    关于空指针:虽然空指针的表示是依赖于实现的,并且不一定是零值,但空指针常量是一个整数常数为零。所以NULL 必须定义为可以转换为零整数值的东西——最明显的定义是0

    【讨论】:

    • 嗯......也许我应该问一下 - Google / MSFT 使用什么?
    • @Hamish:Google 的风格指南并没有涉及那种无关紧要的细节。几十年来,微软有各种古怪的约定,但我很确定他们目前的约定也不担心这样的细节。开明的风格指南应该给出可维护代码的规则,而不是指定如何将代码写到最后一个字符。
    • 这是一个很好的观点。然而,在 C# 的世界中,我很乐意遵循 StyleCop 的规则,这些规则涵盖了最细微的细节,即使我不同意其中的 5%。我希望 C++ 也有类似的东西。
    • @Hamish:这样的工具对于强制执行一致性很有用,但(至少对我而言)与表达性和清晰度相比,它的重要性要小得多。目前,唯一可以检查这些的工具是人脑。代码审查(或者至少是对您自己代码的批判性阅读)比任何样式指南都更能提高质量。
    【解决方案6】:

    我总是喜欢

      if (pSomethingColumn != NULL)
    

    不仅因为它在原则上和概念上是正确的,还因为它是自我记录。仅仅因为“它可以工作”而使用特定的结构是不可移植的必然方法。

    【讨论】:

    • 谢谢,您对 if (NULL == x)if (NULL != x) 等尤达条件有何看法?
    • 我了解 Yoda 表示法的好处,但我觉得它不自然,所以我没有真正采用它。我喜欢以我认为的方式读写代码,这实际上与我的第一个答案一致。
    【解决方案7】:

    NULL 在任何符合 C++ 的编译器中都必须等于 0。就个人而言,我更喜欢使用NULL,因为恕我直言,它更明确,意图更清晰。但是 Bjarne Stroustrup uses 0 而不是 NULL 因为他更喜欢避免使用宏。 C++0x 将有一个明确的 nullptr 关键字,有望一劳永逸地消除这个问题。

    【讨论】:

      【解决方案8】:

      我使用 (!pSomethingColumn) 是因为我很懒惰,但 (pSomethingColumn == NULL) 更具表现力,因为它表明变量是指针。

      【讨论】:

      • 变量名为pSomethingColumn这一事实也是如此。
      • @dreamlax, pSomethingColumn 是我提出这个问题的。我有不透露确切变量名的习惯;我就是这么偏执的。
      • @dreamlax:这只是意味着有人在 1980 年代养成了一个坏习惯。只有变量声明会告诉你它到底是什么类型。
      • 我早就说过,编程中最大的罪行是试图节省一些击键 - 只需学会该死的打字!
      • @James:同意,但也应该避免不会向代码添加任何内容的额外击键。对我来说,伪匈牙利疣和与零的显式比较(尤其是在倒写时)会稍微降低清晰度,因为它会增加噪音但信息很少。有时,如果类型更改时疣没有更新,或者有人使用NULL 而他们的意思是0,那么这些约定就会变得非常具有误导性。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多