你在C ++中使用NULL或0(零)指针?
在C ++的早期,当它被locking在C之上时,你不能使用NULL,因为它被定义为(void*)0
。 除了void*
,你不能将NULL赋值给任何指针,这使得它无用。 在那些日子里,已经接受你使用0
(零)作为空指针。
到目前为止,我一直使用零作为空指针,但是我周围的人坚持使用NULL
。 我个人认为给一个现有的值赋予一个名字( NULL
)没有任何好处 – 因为我也喜欢把指针作为真值来testing:
if (p && !q) do_something();
那么使用零更有意义(如果你使用NULL
,你不能逻辑上使用p && !q
– 你需要明确地比较NULL
,除非你假设NULL
是零,在这种情况下为什么使用NULL
)。
有没有客观的理由更喜欢零(或反之亦然),或者只是个人喜好?
编辑:我应该添加(原本是说)与RAII和exception,我很less使用零/ NULL指针,但有时你仍然需要它们。
这里是Stroustrup的: C ++风格和技巧常见问题
在C ++中,
NULL
的定义是0,所以只有一个美学的区别。 我宁愿避免macros,所以我使用0.NULL
另一个问题是人们有时错误地认为它是从0和/或不是一个整数不同。 在预标准代码中,NULL
有时被定义为不合适的东西,因此必须避免。 这些日子不太常见。如果你必须命名空指针,则称它为
nullptr
; 这就是它在C ++ 11中所称的。 那么,nullptr
将是一个关键字。
也就是说,不要为了小东西而stream汗。
有几个论点(其中一个是相对较新的),我认为这与Bjarne的立场相矛盾。
- 意向文件
使用NULL
允许对其进行search,而且还强调开发人员希望使用NULL
指针,而不pipe它是否被编译器解释为NULL
。
- 指针和“int”的重载比较less见
大家引用的例子是:
void foo(int*); void foo (int); void bar() { foo (NULL); // Calls 'foo(int)' }
不过,至less在我看来,上面的问题并不是我们对空指针常量使用NULL,而是我们有重载“foo”的参数,它们采用了非常不同的参数。 该参数也必须是int
,因为任何其他types都会导致模糊的调用,因此会生成有用的编译器警告。
- 分析工具可以帮助今天!
即使在没有C ++ 0x的情况下,也有一些可用的工具可以validationNULL
是否用于指针,而0
则用于整型。
- C ++ 11将有一个新的
std::nullptr_t
types。
这是表格的最新说法。 对于C ++ 0x, 0
和NULL
的问题正在被主动解决,并且可以保证对于每个提供NULL
实现,他们要做的第一件事是:
#define NULL nullptr
对于那些使用NULL
而不是0
,这种改变将会在types安全性方面有所改进,只需要很less的努力或者没有任何的努力 – 如果有的话,它们也可以在0
使用NULL
来捕获一些错误。 对于任何人今天使用0
…呃…希望他们有正则expression式的良好知识…
使用NULL。 NULL显示你的意图。 这是0是一个实施细节应该不重要。
我停止使用NULL,而不是很久以前(以及其他大多数macros)。 我这样做不仅是因为我想尽可能地避免macros,而且因为NULL似乎已经被C和C ++代码所使用。 这似乎是使用任何时候需要一个0值,而不仅仅是指针。
在新的项目中,我把它放在项目标题中:
static const int nullptr = 0;
现在,当符合C ++ 0x的编译器到达时,我所要做的就是删除该行。 这样做的一个好处是,Visual Studio已经将nullptr识别为关键字并且适当地突出显示它。
我总是使用:
NULL for pointers '\0' for chars 0.0 for floats and doubles
0会做的很好。 这是一个信号意图的问题。 那就是说,我不是肛门的。
cerr << sizeof(0) << endl; cerr << sizeof(NULL) << endl; cerr << sizeof(void*) << endl; ============ On a 64-bit gcc RHEL platform you get: 4 8 8 ================
故事的寓意。 当你处理指针时你应该使用NULL。
1)它声明你的意图(不要让我search你的代码,试图找出一个variables是否是一个指针或一些数字types)。
2)在某些需要可变参数的API调用中,它们将使用NULL指针来指示参数列表的结尾。 在这种情况下,使用“0”而不是NULL可能会导致问题。 在64位平台上,va_arg调用需要一个64位的指针,但是只传递一个32位的整数。 对我来说,就像你依靠其他的32位为你清零? 我见过某些编译器(例如Intel的icpc),这些编译器并不那么亲切 – 这导致了运行时错误。
如果我正确地记得NULL在我使用的标题中定义不同。 对于C,它被定义为(void *)0,对于C ++,它被定义为0。
#ifndef __cplusplus #define NULL (void*)0 #else #define NULL 0 #endif
就我个人而言,我仍然使用NULL值来表示空指针,它使得它明确指出你正在使用一个指针,而不是一些整数types。 是的内部NULL值仍然是0,但它不是这样表示。
此外,我不依赖于整数自动转换为布尔值,但明确地比较它们。
例如,喜欢使用:
if (pointer_value != NULL || integer_value == 0)
而不是:
if (pointer_value || !integer_value)
我们只需要说明这一点,在C ++ 11中可以简单地使用nullptr
而不是NULL
,而且也是nullptr
types的nullptr_t
。
我通常使用0.我不喜欢macros,也不能保证你使用的第三方头不会重新定义NULL是奇怪的。
您可以使用Scott Meyers和其他人提出的nullptr对象,直到C ++获得nullptr关键字:
const // It is a const object... class nullptr_t { public: template<class T> operator T*() const // convertible to any type of null non-member pointer... { return 0; } template<class C, class T> operator TC::*() const // or any type of null member pointer... { return 0; } private: void operator&() const; // Can't take address of nullptr } nullptr = {};
谷歌“nullptr”的更多信息。
我曾经在一台机器上工作,其中0是一个有效的地址,NULL被定义为一个特殊的八进制值。 在那台机器上(0!= NULL),所以代码如
char *p; ... if (p) { ... }
不会像你期望的那样工作。 你必须写
if (p != NULL) { ... }
虽然我相信大多数编译器现在将NULL定义为0,但我还记得那些年前的教训:NULL不一定是0。
我认为标准保证NULL == 0,所以你可以做。 我更喜欢NULL,因为它logging你的意图。
我会说历史已经说了,而那些赞成使用0(零)的人是错误的(包括Bjarne Stroustrup)。 赞成0的论点主要是美学和“个人喜好”。
在创buildC ++ 11之后,有了新的nullptrtypes,一些编译器开始抱怨(使用默认参数)将0传递给带指针参数的函数,因为0不是指针。
如果代码是使用NULL编写的,则可以通过代码库执行简单的search和replace,以使其成为nullptr。 如果你使用0作为指针来编写代码,那么更新它就更加单调乏味了。
如果你现在必须编写新的代码到C ++ 03标准(并且不能使用nullptr),你应该使用NULL。 这将使您在未来更新更容易。
使用0或NULL将具有相同的效果。
但是,这并不意味着它们都是很好的编程实践。 考虑到性能没有差别,select一个低层次的选项而不是不可知的/抽象的select是一个糟糕的编程实践。 帮助你的代码读者理解你的思维过程 。
NULL,0,0.0,'\ 0',0x00和whatelse都转换为相同的东西,但在你的程序中是不同的逻辑实体。 他们应该这样使用。 NULL是一个指针,0是数量,0x0是一个值,其位有趣等你不会分配'\ 0'指针是否编译。
我知道一些社区鼓励通过破坏环境合同来展示对环境的深入了解。 负责任的程序员,但是,使可维护的代码,并保持这些做法的代码。
奇怪的是,没有人,包括Stroustroup提到。 在谈论标准和美学时,没有人注意到在NULL
使用0
是危险的,例如,在sizeof(int) != sizeof(void*)
的体系结构的variables参数列表中。 就像Stroustroup一样,由于美学的原因,我更喜欢0
,但是我们应该小心,不要在types可能模糊的地方使用它。
我尝试通过在可能的情况下使用C ++引用来避免整个问题。 而不是
void foo(const Bar* pBar) { ... }
你可能经常能写
void foo(const Bar& bar) { ... }
当然,这并不总是工作。 但空指针可以被过度使用。
我和Stroustrup在这一个:-)由于NULL不是语言的一部分,我更喜欢使用0。
我更喜欢使用NULL,因为它表明你的意图是值表示一个指针而不是一个算术值。 这是一个macros观的事实是不幸的,但由于它是如此广泛的根深蒂固,没有什么危险(除非有人做了一些真正的骨头)。 我希望它从一开始就是一个关键字,但你能做什么?
也就是说,我用指针作为真值本身没有问题。 就像NULL一样,这是一个根深蒂固的成语。
C ++ 09将会添加我认为应该迟到的nullptr结构。
大多数情况下,个人偏好,虽然可以使NULL的说法很明显,该对象是一个指针,目前不指向任何东西,例如
void *ptr = &something; /* lots o' code */ ptr = NULL; // more obvious that it's a pointer and not being used
IIRC,标准并不要求NULL为0,所以使用<stddef.h>中定义的任何内容对您的编译器来说可能是最好的。
争论的另一个方面是你是否应该使用逻辑比较(隐式转换为bool)或者显式检查NULL,但这也归结为可读性。
我总是使用0.不是任何真正想到的理由,只是因为当我第一次学习C ++时,我阅读了一些推荐使用0的东西,而且我总是这样做。 从理论上讲,可读性是一个混淆的问题,但在实践中我从来没有遇到过几千个工时和几百万行代码的问题。 正如Stroustrup所说,在标准变为nullptr之前,这只是个人的美学问题。
有人告诉我一次…我要重新定义NULL为69.从那时起我不使用它:P
它使你的代码非常脆弱。
编辑:
并非标准中的所有内容都是完美的。 macrosNULL是一个实现定义的C ++空指针常量,与C NULLmacros不完全兼容,除了types隐藏隐式转换它在一个无用的和容易出错的工具。
NULL不performance为空指针,而是O / OL文字。
告诉我下一个例子并不令人困惑:
void foo(char *); void foo(int); foo(NULL); // calls int version instead of pointer version!
是因为这一点,在新的标准出现std :: nullptr_t
如果你不想等待新标准,并想使用nullptr,那么至less应该使用像Meyers所build议的那样的体系(见jon.h comment)。
那么我认为只要有可能就不要使用0或NULL指针。
使用它们迟早会导致代码中的分段错误。 根据我的经验,gereral中的指针是C ++中最大的bug之一
另外,它会导致遍布代码的“if-not-null”语句。 如果你总是可以依赖一个有效的状态,那就好多了。
几乎总是有一个更好的select。
将指针设置为0就不那么清楚了。 尤其是如果你使用C ++以外的语言。 这包括C以及Javascript。
我最近删除了这样的代码:
virtual void DrawTo(BITMAP *buffer) =0;
为纯虚function首次。 我认为这是一个星期的一些神奇的jiberjash。 当我意识到它只是基本上将函数指针设置为null
(因为在大多数情况下,对于C ++来说,虚函数只是函数指针),我踢了自己。
virtual void DrawTo(BITMAP *buffer) =null;
如果没有适当的间距,我的新眼睛可能会比那种枯燥乏味的东西混乱。 实际上,我想知道为什么C ++不使用小写的null
,就像现在使用小写的false和true一样。