在最近的代码审查中,贡献者试图强制执行对指针的所有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)
这对于查找和调试来说只是一种绝对的痛苦。
您更喜欢哪种方式?为什么?
答案 0 :(得分:182)
根据我的经验,首选if (ptr)
或if (!ptr)
形式的测试。它们不依赖于符号NULL
的定义。他们没有暴露意外分配的机会。它们清晰简洁。
编辑:正如SoapBox在评论中指出的那样,它们与诸如auto_ptr
之类的C ++类兼容,这些类是充当指针并提供到{{1}的转换的对象准确地启用这个成语。对于这些对象,与bool
的显式比较必须调用转换为指针,这可能具有其他语义副作用,或者比NULL
转换所暗示的简单存在检查更昂贵。
我偏爱代码,说明没有不需要的文本意味着什么。 bool
与if (ptr != NULL)
具有相同的含义,但代价是多余的特异性。下一个合乎逻辑的事情是写if (ptr)
,这就是疯狂。 C语言很清楚,if ((ptr != NULL) == TRUE)
,if
等测试的布尔值具有非零值的特定含义为真,零为假。冗余并没有让它更清晰。
答案 1 :(得分:50)
if (foo)
足够清楚了。使用它。
答案 2 :(得分:24)
我将从这开始:一致性是王道,决定不如你的代码库中的一致性重要。
在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中,NULL可以定义为0或((void *)0),C99允许实现定义的空指针常量。所以它实际上归结为实现的NULL定义,你必须在标准库中检查它。
宏是非常常见的,一般来说,它们用于弥补语言和其他方面的泛型编程支持的不足。语言更简单,对预处理器的依赖更为常见。
从这个角度来看,我可能建议在C中使用NULL
宏定义。
答案 3 :(得分:19)
我使用if (ptr)
,但这完全不值得争论。
我喜欢自己的方式,因为它很简洁,但有些人说== NULL
使阅读更容易,更明确。我看到他们来自哪里,我只是不同意额外的东西让它变得更容易。 (我讨厌宏观,所以我有偏见。)由你决定。
我不同意你的论点。如果您没有收到有条件的分配警告,则需要提高警告级别。就那么简单。 (为了所有善的爱,不要转换它们。)
注意在C ++ 0x中,我们可以if (ptr == nullptr)
,这对我来说 读得更好。 (再一次,我讨厌宏。但是nullptr
很好。)我仍然会if (ptr)
,只是因为它是我习惯的。
答案 4 :(得分:9)
如果您计划识别错误而不继续执行该函数(即,您将抛出异常或立即返回错误代码),您应该将其作为保护条款:
int f(void* p)
{
if (!p) { return -1; }
// p is not null
return 0;
}
这样,您就可以避免使用“箭头代码”。
答案 5 :(得分:7)
我个人总是使用if (ptr == NULL)
,因为它使我的意图明确,但此时这只是一种习惯。
使用=
代替==
将被具有正确警告设置的任何合格编译器捕获。
重点是为您的团队选择一致的风格并坚持下去。无论你走哪条路,你最终会习惯它,并且欢迎在使用其他人的代码时失去摩擦力。
答案 6 :(得分:7)
还有一点支持foo == NULL
练习:
如果foo
是int *
或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 ++不会在if
,for
和while
语句中检查布尔条件中的类型。我总是使用以下内容:
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只是一个真/假标志。