关闭。这个问题是基于意见的。它目前不接受答案。想改进这个问题?更新问题,以便可以通过编辑这篇文章用事实和引用来回答它。 7年前关闭。改进这个问题
在最近的一次代码审查中,一位贡献者试图强制以下列方式对指针执行所有 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)
这只是查找和调试的绝对痛苦。
你更喜欢哪种方式,为什么?
根据我的经验,if (ptr)
或 if (!ptr)
形式的测试是首选。它们不依赖于符号 NULL
的定义。他们不会暴露意外分配的机会。它们清晰简洁。
编辑: 正如 SoapBox 在评论中指出的那样,它们与 C++ 类(例如 auto_ptr
)兼容,这些类是充当指针的对象,并提供到 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,我不确定他是否也做过比较,我已经有一段时间没有读过这本书了,我想他只是做过{4 } 没有明确的比较,但我对此很模糊。
原因是 NULL
宏具有欺骗性(几乎所有宏都是)它实际上是 0
字面量,而不是顾名思义的唯一类型。避免使用宏是 C++ 中的一般准则之一。另一方面,0
看起来像一个整数,与指针比较或分配给指针时它不是。就我个人而言,我可以选择任何一种方式,但通常我会跳过显式比较(尽管有些人不喜欢这个,这可能就是为什么你有贡献者建议改变的原因)。
不管个人感觉如何,这在很大程度上是一种最不邪恶的选择,因为没有一种正确的方法。
这很清楚,是一个常见的习惯用法,我更喜欢它,在比较过程中不会意外分配一个值,并且读起来很清楚:
if (some_ptr) {}
如果您知道 some_ptr
是指针类型,这很清楚,但它也可能看起来像整数比较:
if (some_ptr != 0) {}
这很清楚,在通常情况下它是有道理的......但它是一个泄漏的抽象,NULL
实际上是 0
字面量,最终可能很容易被滥用:
if (some_ptr != NULL) {}
C++11 有 nullptr
现在是首选方法,因为它明确且准确,请注意意外分配:
if (some_ptr != nullptr) {}
在您能够迁移到 C++0x 之前,我认为担心您使用这些方法中的哪一种是浪费时间,它们都是不够的,这就是发明 nullptr 的原因(以及提出完美转发的通用编程问题.) 最重要的是保持一致性。
在 C 中
C是另一种野兽。
在 C 中 NULL
可以定义为 0
或 ((void *)0)
,C99 允许实现定义空指针常量。所以它实际上归结为 NULL
的实现定义,您必须在标准库中检查它。
宏非常常见,通常它们被大量用于弥补语言和其他事物中通用编程支持的不足。该语言更简单,对预处理器的依赖更普遍。
从这个角度来看,我可能会建议在 C 中使用 NULL
宏定义。
0
是正确的,但它在 C:(void *)0
中具有意义。在 C++ 中,0
优于 NULL
,因为类型错误可能是 PITA。
NULL
无论如何都是零。
linux/stddef.h
的 #define NULL ((void *)0)
NULL
必须为零。
我使用if (ptr)
,但这完全不值得争论。
我喜欢我的方式,因为它简洁,尽管其他人说 == NULL
使它更容易阅读和更明确。我知道他们来自哪里,我只是不同意额外的东西让它变得更容易。 (我讨厌宏观,所以我有偏见。)由你决定。
我不同意你的论点。如果您没有收到条件分配的警告,则需要提高警告级别。就那么简单。 (为了所有美好事物的热爱,请不要调换它们。)
请注意,在 C++0x 中,我们可以执行 if (ptr == nullptr)
,这对我来说确实读起来更好。 (再说一次,我讨厌宏。但是 nullptr
很好。)不过,我仍然使用 if (ptr)
,只是因为它是我习惯的。
坦率地说,我不明白它为什么重要。任何一个都非常清楚,任何对 C 或 C++ 有一定经验的人都应该理解两者。不过,有一条评论:
如果您打算识别错误并且不继续执行该函数(即,您将立即抛出异常或返回错误代码),则应将其设为保护子句:
int f(void* p)
{
if (!p) { return -1; }
// p is not null
return 0;
}
这样,您就可以避免“箭头代码”。
if(!p)
是未定义的行为。它可以工作或不工作。
if(!p)
不是未定义的行为,而是它之前的行。 if(p==NULL)
也会有完全相同的问题。
就我个人而言,我一直使用 if (ptr == NULL)
,因为它使我的意图明确,但在这一点上,这只是一种习惯。
使用 =
代替 ==
将被具有正确警告设置的任何合格编译器捕获。
重要的是为您的团队选择一致的风格并坚持下去。不管你走哪条路,你最终都会习惯它,并且在使用其他人的代码时减少摩擦是受欢迎的。
还有一点支持 foo == NULL
实践:如果 foo
是 int *
或 bool *
,那么 if (foo)
检查可能会被读者意外解释为测试指针,即if (*foo)
。此处的 NULL
比较提醒我们正在讨论指针。
但我想一个好的命名约定会让这个论点变得毫无意义。
The C Programming Language (K&R) 会让您检查 null == ptr 以避免意外分配。
if (!valid)
高于 if (valid == 0
)。
实际上,我使用这两种变体。
在某些情况下,您首先检查指针的有效性,如果它为 NULL,您只需返回/退出函数。 (我知道这会导致讨论“一个函数是否应该只有一个出口点”)
大多数时候,您检查指针,然后做您想做的事,然后解决错误情况。结果可能是带有多个 if 的丑陋的 x 倍缩进代码。
goto
可能非常方便。此外,在许多情况下,需要清理的 malloc()
可以替换为更快的 alloca()
。我知道不推荐它们,但它们的存在是有原因的(对我来说,goto
的命名标签比混淆的 if/else
树要干净得多)。
alloca
是非标准且完全不安全的。如果它失败了,你的程序就会崩溃。没有恢复的机会,而且由于堆栈相对较小,很可能会失败。失败时,您可能会破坏堆并引入损害特权的漏洞。切勿使用 alloca
或 vlas,除非您对将要分配的大小进行了 tiny 限制(然后您不妨只使用普通数组)。
如果样式和格式将成为您评论的一部分,则应该有一个商定的样式指南来衡量。如果有,请按照样式指南的说明进行操作。如果没有,像这样的细节应该在写的时候留下。这是浪费时间和精力,并且分散了代码审查真正应该发现的内容。说真的,如果没有样式指南,我原则上不会更改这样的代码,即使它不使用我喜欢的约定。
这并不重要,但我个人的偏好是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
通过预先处理异常情况,我可以处理它,然后忘记它。但是如果我不能通过预先处理它来回到快乐的道路上,那么它应该在主要案例之后处理,因为它使代码更容易理解。在我看来。
但如果它不在风格指南中,那么这只是我的意见,你的意见同样有效。要么标准化,要么不标准化。不要让审阅者仅仅因为他有意见就伪标准化。
{}
。
这是两种语言的基础之一,指针评估为可用作控制表达式的类型和值,C++ 中的 bool
和 C 中的 int
。只需使用它。
指针不是布尔值
当您意外编写 if (foo = bar) 时,现代 C/C++ 编译器会发出警告。
所以我更喜欢
if (foo == NULL)
{
// null case
}
else
{
// non null case
}
或者
if (foo != NULL)
{
// non null case
}
else
{
// null case
}
但是,如果我正在编写一套风格指南,我不会在其中添加这样的内容,我会添加如下内容:
确保对指针进行空检查。
我非常喜欢 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 只是一个真/假标志。
我使用的大多数编译器至少会在 if
分配上发出警告,而无需进一步的语法糖,所以我不买那个论点。也就是说,我已经专业地使用了这两种方法,并且对任何一种都没有偏好。在我看来,== NULL
肯定更清晰。
int y = *x; if (!x) {...}
,其中允许优化器推断,因为如果x
为 NULL,则*x
将未定义,因此它不能为 NULL,因此!x
必须为 FALSE。表达式!ptr
是 not 未定义的行为。在示例中,如果测试是在在任何使用*x
之前进行的,那么优化器将错误地消除测试。