首页 文章

检查C / C中的NULL指针[关闭]

提问于
浏览
134

在最近的代码审查中,贡献者试图强制执行对指针的所有 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
}

我同意他的方式稍微清楚一点,因为's explicitly saying 805257 , but I would counter that by saying that anyone who'在这段代码上工作会明白在 if 语句中使用指针变量会隐式检查 NULL . 另外我觉得第二种方法引入类似错误的可能性较小:

if (some_ptr = NULL)

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

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

15 回答

  • 170
    • 指针不是布尔值

    • 当您意外写入 if (foo = bar) 时,现代C / C编译器会发出警告 .

    所以我更喜欢

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

    要么

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

    但是,如果我正在编写一套样式指南,我就不会在其中加入这样的内容,我会说:

    确保对指针进行空检查 .

  • 1

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

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

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

  • 3

    if (foo) 足够清楚了 . 用它 .

  • 9

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

    在C.

    NULL在C中定义为0或0L .

    如果你读过C编程语言Bjarne Stroustrup suggests using 0 explicitly to avoid the NULL macro when doing assignment,我读了这本书已经有一段时间了,我认为他只是做了 if(some_ptr) 而没有明确的比较,但我对此很模糊 .

    原因是 NULL 宏具有欺骗性(几乎所有的宏都是)它实际上是 0 literal,而不是名称所暗示的唯一类型 . 避免使用宏是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 宏定义 .

  • 1

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

    我喜欢我的方式,因为它简洁,但其他人说 == NULL 使它更容易阅读和更明确 . 我看到他们偏向哪里 . )由你决定 .

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

    注意在C 0x中,我们可以做 if (ptr == nullptr) ,这对我来说确实读得更好 . (再一次,我讨厌宏 . 但是 nullptr 很好 . )我仍然做 if (ptr) ,只是因为它曾经是's what I' .

  • 4

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

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

    int f(void* p)
    {
        if (!p) { return -1; }
    
        // p is not null
        return 0;
    }
    

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

  • 6

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

    但我认为一个好的命名约定使这个论点没有实际意义 .

  • 22

    我个人总是使用 if (ptr == NULL) 因为它使我的意图明确,但在这一点上它只是一个习惯 .

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

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

  • 49

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

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

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

  • 1

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

  • 5

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

    并不重要,但我个人的偏好是 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
    

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

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

  • 4

    我认为这很清楚:

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

    读它为"If there is no pointer ..."

    此外,它简洁,没有意外分配的危险 .

  • 1

    这是两种语言的基础之一,指针评估的类型和值可以用作控制表达式,C中的 bool 和C中的 int 只需使用它 .

  • 1

    我'm a huge fan of the fact that C/C++ doesn' t检查 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只是一个真/假标志 .

  • 18

    我使用过的大多数编译器至少会在没有进一步语法糖的情况下对 if 赋值进行警告,因此我不会专业地使用这两种编译器,也没有偏好 . 在我看来, == NULL 绝对更清晰 .

相关问题