在C / C ++中检查NULL指针
在最近的代码审查中,贡献者试图强制指针上的所有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)
这只是一个绝对的痛苦find和debugging。
你喜欢哪种方式,为什么?
根据我的经验,表单if (ptr)
或if (!ptr)
是首选。 它们不依赖于符号NULL
的定义。 他们没有暴露意外分配的机会。 他们是清晰和简洁的。
编辑: SoapBox在评论中指出,它们与C ++类(如auto_ptr
兼容,它们是充当指针的对象,它们提供了一个转换为bool
来准确地启用这个习惯用法。 对于这些对象,与NULL
的显式比较将不得不调用对指针的转换,其可能具有其他语义副作用或比bool
转换暗示的简单存在检查更昂贵。
我有一个偏好的代码,说什么意思,没有不必要的文字。 if (ptr != NULL)
与if (ptr)
if (ptr != NULL)
具有相同的含义,但代价是冗余特异性。 下一个合乎逻辑的事情就是写if ((ptr != NULL) == TRUE)
,那就是疯狂。 C语言很清楚,通过if
, while
等testing的布尔值具有非零值的特定含义为true,零为false。 冗余并没有使它更清晰。
if (foo)
足够清楚。 用它。
我用if (ptr)
,但这完全不值得争论。
我喜欢我的方式,因为它是简洁的,虽然别人说== NULL
使得它更容易阅读和更明确。 我看到他们来自哪里,我只是不同意多余的东西,这使得它更容易。 (我讨厌macros,所以我很偏向)。
我不同意你的观点。 如果您没有在条件中获得任务警告,则需要将警告级别提高。 就那么简单。 (为了一切美好的爱,不要把它们切换。)
注意在C ++ 0x中,我们可以做if (ptr == nullptr)
,这对我来说读起来更好。 (再次,我讨厌这个macros,但是nullptr
是很好的。)但是, if (ptr)
,我仍然这样做,只是因为这是我习惯的。
我将从此开始:一致性是王道,决定并不比代码库中的一致性重要。
在C ++中
在C ++中,NULL被定义为0或0L。
如果你已经阅读过C ++编程语言 Bjarne Stroustrupbuild议在做任务时明确使用0
来避免NULL
macros ,但我不确定他是否在比较时也是这样,从我读这本书以来已经有一段时间了,我想他只是if(some_ptr)
没有明确的比较,但我很模糊。
原因是NULL
macros是欺骗性的(几乎所有的macros),它实际上是0
字面的,而不是名字所暗示的唯一types。 避免macros是C ++中的一般准则之一。 另一方面, 0
看起来像一个整数,它不是比较或分配给指针。 就个人而言,我可以去任何一种方式,但通常我会略过明确的比较(尽pipe有些人不喜欢这可能是为什么你有一个贡献者build议改变)。
不pipe个人的感受如何,这在很大程度上是一个最不起眼的select,因为没有一个正确的方法。
这是一个很明显的习惯用法,我更喜欢它,在比较过程中没有意外分配一个值的机会,
if(some_ptr){;}
如果你知道some_ptr
是一个指针types,那么这很清楚,但是它也可能看起来像一个整数比较:
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的实现定义,您将不得不在标准库中检查它。
macros是非常常见的,一般来说,它们被用来弥补语言和其他方面对通用编程支持的不足。 语言要简单得多,而且对预处理器的依赖更为普遍。
从这个angular度来看,我可能会build议在C中使用NULL
macros定义
坦率地说,我不明白为什么它很重要。 任何一个都很清楚,任何有C或C ++经验的人都应该理解这两者。 但有一点意见:
如果您打算识别错误并且不继续执行该函数(即,您将立即抛出exception或返回错误代码),则应该使其成为警戒条款:
int f(void* p) { if (!p) { return -1; } // p is not null return 0; }
这样,你避免了“箭头代码”。
其实,我使用这两个变种。
有些情况下,你首先检查一个指针的有效性,如果它是NULL,你只是返回/退出一个函数。 (我知道这可能导致讨论“如果一个函数只有一个退出点”)
大多数时候,你检查指针,然后做你想要的,然后解决错误的情况下。 结果可能是带有多个if的难看的x次缩进代码。
就个人而言,我一直使用if (ptr == NULL)
因为它使我的意图明确,但在这一点上,这只是一个习惯。
使用=
代替==
将被任何主pipe编译器捕获,并具有正确的警告设置。
重要的一点是为你的团队select一致的风格并坚持下去。 无论你走哪条路,你最终都会习惯,而且在其他人的代码中工作时会失去摩擦。
如果风格和格式将成为您的评论的一部分,应该有一个商定的风格指南来衡量。 如果有的话,请按照风格指南的说法进行操作。 如果没有一个,像这样的细节应该留下,因为他们写。 这是浪费时间和精力,并分散了代码评论真正应该发现的。 严重的是,没有一个风格指南,我会推动不要改变这样的代码作为一个原则问题,即使它不使用我喜欢的惯例。
而不是那么重要,但是我的个人偏好是if (ptr)
。 即使if (ptr == NULL)
这个意思对我来说也是比较明显的。
也许他试图说,在快乐之路之前处理错误情况会更好? 在这种情况下,我仍然不同意审稿人。 我不知道这是否有一个公认的惯例,但在我看来,任何声明都应该是最“正常”的条件。 这样一来,我就没有多less工夫去弄清楚这个function是什么,它是如何工作的。
这是一个例外,如果错误导致我从函数中保释,或者我可以在继续之前从中恢复。 在这些情况下,我首先处理错误:
if (error_condition) bail_or_fix(); return if not fixed; // If I'm still here, I'm on the happy path
通过处理不寻常的情况,我可以照顾它,然后忘掉它。 但是,如果我不能通过前面的处理来回到快乐的道路上,那么它应该在主要情况之后处理,因为它使得代码更容易理解。 我的想法是。
但是,如果它不是一个风格指南,那么这只是我的意见,你的意见是一样的有效。 要么标准化,要么没有。 不要让审稿人因为他有意见而伪造标准化。
只是有一点赞成foo == NULL
做法:如果foo
是一个int *
或一个bool *
,那么if (foo)
检查可能被读者意外地解释为testing指针的值,即如if (*foo)
。 这里的NULL
比较提醒我们正在讨论一个指针。
但是我认为一个好的命名约定使得这个论点没有意义。
C编程语言 (K&R)将让你检查null == ptr,以避免意外的分配。
我觉得这很清楚:
if( !some_ptr ) { // handle null-pointer error } else { // proceed }
阅读它为“如果没有指针…”
另外它简洁,没有意外分配的危险。
这是两种语言的基本原理之一,指针评估的types和值可以用作控制expression式,C ++中的bool
和C中的int
。只需使用它即可。
我对C / C ++不检查if
, for
和while
语句中的布尔条件中的types的事实非常感兴趣。 我总是使用以下内容:
if (ptr) if (!ptr)
即使在整数或其他types转换为布尔:
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只是一个真/假标志。
我用过的大多数编译器至less会在没有进一步的语法糖的情况下对这个赋值语句提出警告,所以我不会买这个说法。 也就是说,我既专业地使用,也没有偏好。 == NULL
在我看来是绝对清晰的。
- 指针不是布尔值
- 现代的C / C ++编译器会在你写
if (foo = bar)
的时候发出警告。
所以我比较喜欢
if (foo == NULL) { // null case } else { // non null case }
要么
if (foo != NULL) { // non null case } else { // null case }
但是,如果我正在编写一套风格指南,我不会把这样的东西放在里面,我会把这样的东西放在:
确保你对指针进行了空检查。