在最近的代码审查中,贡献者试图强制执行对指针的所有 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 回答
指针不是布尔值
当您意外写入
if (foo = bar)
时,现代C / C编译器会发出警告 .所以我更喜欢
要么
但是,如果我正在编写一套样式指南,我就不会在其中加入这样的内容,我会说:
根据我的经验,首选
if (ptr)
或if (!ptr)
形式的测试 . 它们不依赖于符号NULL
的定义 . 他们没有暴露意外分配的机会 . 它们清晰简洁 .Edit: 正如SoapBox在评论中指出的那样,它们与诸如
auto_ptr
之类的C类兼容,这些类是充当指针的对象,并且提供到bool
的转换以准确地实现这个成语 . 对于这些对象,与NULL
的显式比较必须调用转换为指针,该指针可能具有其他语义副作用,或者比bool
转换所暗示的简单存在检查更昂贵 .我偏爱代码,说明没有不需要的文本意味着什么 .
if (ptr != NULL)
具有与if (ptr)
相同的含义,但代价是冗余特异性 . 下一个合乎逻辑的事情是写if ((ptr != NULL) == TRUE)
,那就是疯狂 . C语言很清楚,if
,while
等测试的布尔值具有非零值的特定含义为真,零为假 . 冗余并没有让它更清晰 .if (foo)
足够清楚了 . 用它 .我将从这开始:一致性是王道,决定不如你的代码库中的一致性重要 .
在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
看起来像一个整数,并且在与指针比较或分配时不会 . 我个人可以去任何一种方式,但通常我会跳过明确的比较(尽管有些人不喜欢这个,这可能就是为什么你有一个贡献者提出改变的原因) .无论个人感受如何,这都是最不邪恶的选择,因为没有一种正确的方法 .
这很清楚,也是一个常见的习惯用语,我更喜欢它,在比较期间没有意外分配值的可能性,它清楚地显示:
如果你知道
some_ptr
是一个指针类型,这很明显,但它也可能看起来像一个整数比较:这是明确的,在通常情况下它是有道理的...但它是一个漏洞的抽象,
NULL
实际上是0
字面意思,最终可能容易被误用:C 0x有nullptr,它现在是首选方法,因为它是明确和准确的,只需注意意外分配:
在你能够迁移到C 0x之前,我认为浪费时间来担心你使用哪种方法,它们都是不足以解释为什么会发明nullptr(以及通用编程问题,它提出了完美的转发 . )最重要的是保持一致性 .
在C.
C是一个不同的野兽 .
在C中,NULL可以定义为0或((void *)0),C99允许实现定义的空指针常量 . 所以它实际上归结为实现的NULL定义,你必须在标准库中检查它 .
宏是非常常见的,并且通常它们被用于弥补语言和其他方面的泛型编程支持的不足 . 语言更简单,对预处理器的依赖更为常见 .
从这个角度来看,我可能建议在C中使用
NULL
宏定义 .我使用
if (ptr)
,但这完全不值得争论 .我喜欢我的方式,因为它简洁,但其他人说
== NULL
使它更容易阅读和更明确 . 我看到他们偏向哪里 . )由你决定 .我不同意你的论点 . 如果您没有收到有条件的分配警告,则需要提高警告级别 . 就那么简单 . (为了所有善良的爱,不要转换它们 . )
注意在C 0x中,我们可以做
if (ptr == nullptr)
,这对我来说确实读得更好 . (再一次,我讨厌宏 . 但是nullptr
很好 . )我仍然做if (ptr)
,只是因为它曾经是's what I' .坦率地说,我不明白为什么这很重要 . 任何一个都很清楚,任何适度使用C或C的人都应该理解这两者 . 但有一条评论:
如果您计划识别错误而不继续执行该函数(即,您将抛出异常或立即返回错误代码),您应该将其作为保护条款:
这样,您就可以避免使用“箭头代码” .
还有一点支持
foo == NULL
练习:如果foo
是int *
或bool *
,那么if (foo)
检查可能被读者意外解释为测试指针对象的值,即if (*foo)
. 这里的NULL
比较提醒我们,我们正在谈论一个指针 .但我认为一个好的命名约定使这个论点没有实际意义 .
我个人总是使用
if (ptr == NULL)
因为它使我的意图明确,但在这一点上它只是一个习惯 .使用
=
代替==
将被具有正确警告设置的任何合格编译器捕获 .重要的是为您的团队选择一致的风格并坚持下去 . 无论你走哪条路,你最终会习惯它,并且欢迎在使用其他人的代码时失去摩擦力 .
实际上,我使用两种变体 .
在某些情况下,您首先检查指针的有效性,如果它是NULL,您只需返回/退出函数 . (我知道这可以导致讨论“如果一个函数只有一个退出点”)
大多数情况下,您检查指针,然后执行您想要的操作,然后解决错误情况 . 结果可能是丑陋的x次缩进代码,带有多个if .
The C Programming Language(K&R)会检查null == ptr以避免意外分配 .
如果样式和格式将成为您评论的一部分,那么应该有一个商定的风格指南来衡量 . 如果有,请按照样式指南说 . 如果没有,那么应该保留这样的细节 . 这是浪费时间和精力,并且分散了代码审查真正应该发现的内容 . 说真的,如果没有样式指南,我会推动不改变这样的代码作为原则问题,即使它不使用我喜欢的惯例 .
并不重要,但我个人的偏好是
if (ptr)
. 对于我来说,这个含义甚至比if (ptr == NULL)
更明显 .也许他试图说在快乐路径之前处理错误状况会更好?在那种情况下,我仍然不同意审稿人 . 我不知道有一个公认的惯例,但在我看来,最“正常”的条件应该在任何if语句中排在第一位 . 这样我就可以更少地去弄清楚功能是什么以及它是如何工作的 .
例外情况是如果错误导致我从函数中保释,或者我可以在继续之前从中恢复 . 在这些情况下,我会先处理错误:
通过预先处理异常情况,我可以照顾它然后忘记它 . 但是如果我不能通过预先处理它来回到快乐的道路上,那么它应该在主要案例之后处理,因为它使代码更容易理解 . 在我看来 .
但如果它不是风格指南那么这只是我的意见,你的意见同样有效 . 标准化或不标准化 . 不要让审稿人伪标准化只是因为他有意见 .
我认为这很清楚:
读它为"If there is no pointer ..."
此外,它简洁,没有意外分配的危险 .
这是两种语言的基础之一,指针评估的类型和值可以用作控制表达式,C中的
bool
和C中的int
只需使用它 .我'm a huge fan of the fact that C/C++ doesn' t检查
if
,for
和while
语句中布尔条件的类型 . 我总是使用以下内容:甚至在转换为bool的整数或其他类型上:
这种风格的编码对我来说更具可读性和清晰度 . 只是我个人的意见 .
最近,在使用OKI 431微控制器时,我注意到以下内容:
效率比
因为在以后的情况下,编译器必须将chx的值与1进行比较 . 其中chx只是一个真/假标志 .
我使用过的大多数编译器至少会在没有进一步语法糖的情况下对
if
赋值进行警告,因此我不会专业地使用这两种编译器,也没有偏好 . 在我看来,== NULL
绝对更清晰 .