在c++中指针使用NULL或0(零)吗?

在c++的早期,当它被固定在C之上时,你不能使用NULL,因为它被定义为(void*)0。你不能将NULL赋值给除void*之外的任何指针,这使得它有点无用。在过去,使用0 (zero)作为空指针是被接受的。

直到今天,我仍然使用0作为空指针,但我周围的人坚持使用NULL。我个人认为给现有值命名(NULL)没有任何好处-因为我也喜欢将指针作为真值测试:

if (p && !q)
do_something();

那么使用0就更有意义了(比如如果你使用NULL,你就不能在逻辑上使用p && !q——你需要显式地与NULL进行比较,除非你假设NULL为零,在这种情况下为什么要使用NULL)。

是否有任何客观的原因让人们更喜欢0而不是NULL(反之亦然),或者这只是个人偏好?

编辑:我应该补充(最初的意思是说),对于RAII和异常,我很少使用零/NULL指针,但有时你仍然需要它们。

150408 次浏览

我认为标准保证NULL == 0,所以你可以做任何一件事。我更喜欢NULL,因为它记录了您的意图。

下面是Stroustrup对此的看法:c++风格和技术常见问题解答

在c++中,NULL的定义是0,所以只有美学上的区别。我更喜欢避免宏,所以我使用0。NULL的另一个问题是,人们有时会错误地认为它不同于0和/或不是整数。在标准之前的代码中,NULL有时被定义为不合适的东西,因此必须/必须避免。现在这种情况不常见了。

如果必须为空指针命名,则将其命名为nullptr;这是c++ 11里的叫法。然后,nullptr将是一个关键字。

也就是说,不要为小事烦恼。

我曾经在一台机器上工作,其中0是一个有效地址,NULL被定义为一个特殊的八进制值。在该机器上(0 != NULL),因此代码如

char *p;


...


if (p) { ... }

不会如你所愿。你必须写

if (p != NULL) { ... }

虽然我相信现在大多数编译器都将NULL定义为0,但我仍然记得那些年前的教训:NULL不一定是0。

如果我回忆正确,NULL在我使用的头中定义不同。对于C,它被定义为(void*)0,而对于c++,它被定义为0。代码看起来像这样:

#ifndef __cplusplus
#define NULL (void*)0
#else
#define NULL 0
#endif

就我个人而言,我仍然使用NULL值来表示空指针,这表明你使用的是指针而不是某种整型。是的,在内部NULL值仍然是0,但它不是这样表示的。

此外,我不依赖于整数到布尔值的自动转换,而是显式地比较它们。

例如,更喜欢使用:

if (pointer_value != NULL || integer_value == 0)

而不是:

if (pointer_value || !integer_value)

可以这么说,这在c++ 11中都得到了补救,可以简单地使用nullptr而不是NULL,还有nullptr_t,它是nullptr的类型。

我同意Stroustrup的观点:-) 由于NULL不是语言的一部分,我更喜欢使用0.

主要是个人偏好,尽管有人可能会说,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,因为它清楚地表明,您的意图是值表示指针而不是算术值。不幸的是,它是一个宏,但由于它是如此广泛地根深蒂固,几乎没有什么危险(除非有人做了一些非常愚蠢的事情)。我希望从一开始它就是一个关键字,但是你能做什么呢?

也就是说,我对使用指针本身作为真值没有问题。就像NULL一样,这是一个根深蒂固的习惯用语。

c++ 09将添加nullptr构造,我认为这是早就该有的。

我很久以前就停止使用NULL而改用0了(以及大多数其他宏)。我这样做不仅是因为我想尽可能地避免宏,还因为NULL似乎在C和c++代码中被过度使用了。它似乎被用于任何需要0值的地方,而不仅仅是指针。

在新项目中,我把这个放在项目头中:

static const int nullptr = 0;
现在,当c++ 0x兼容的编译器到来时,我所要做的就是删除这一行。 这样做的一个好处是Visual Studio已经将nullptr识别为关键字,并适当地突出显示它

使用NULL。NULL表示你的意图。它是0是一个实现细节,应该无关紧要。

我总是用:

  • NULL用于指针
  • '\0'用于字符
  • 0.0用于浮点数和双精度数

0就可以了。这是一个传达意图的问题。话虽如此,我对此并不感兴趣。

我认为有一些论点(其中一个是最近的)与Bjarne在这方面的立场相矛盾。

  1. < p > 意向文件

    使用NULL允许搜索它的使用情况,并且它还强调开发人员想要使用NULL指针,而不管它是否被编译器解释为NULL

  2. < p > 指针和'int'的重载相对较少

    大家都引用的例子是:

     void foo(int*);
    void foo (int);
    
    
    void bar() {
    foo (NULL);  // Calls 'foo(int)'
    }
    

    然而,至少在我看来,上面的问题不在于我们使用NULL作为空指针常量:而是我们有foo()的重载,它们采用非常不同的参数类型。形参也必须是int,因为任何其他类型都会导致有歧义的调用,从而生成有用的编译器警告。

  3. < p > 分析工具可以帮助今天!

    即使在没有c++ 0x的情况下,现在也有工具可以验证NULL是否用于指针,0是否用于整型。

  4. < p > c++ 11将有一个新的std::nullptr_t类型。

    这是表中最新的参数。c++ 0x正在积极解决0NULL的问题,你可以保证,对于提供NULL的每个实现,它们要做的第一件事是:

     #define NULL  nullptr
    

    对于那些使用NULL而不是0的人来说,这个变化将是类型安全方面的一个改进——如果有的话,它可能还会捕捉到一些他们在0中使用NULL的错误。对于今天使用0的任何人…嗯,希望他们对正则表达式有很好的了解……

我通常用0。我不喜欢宏,而且不能保证您使用的某些第三方头文件不会将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 T C::*() const   // or any type of null member pointer...
{ return 0; }


private:
void operator&() const;  // Can't take address of nullptr


} nullptr = {};

谷歌"nullptr"获取更多信息。

我尽量使用c++参考来避免整个问题。而不是

void foo(const Bar* pBar) { ... }

你可能经常会写作

void foo(const Bar& bar) { ... }

当然,这并不总是有效的;但是空指针可能会被过度使用。

曾经有人告诉我……我将把NULL重新定义为69。从那以后,我不再使用它:P

它使您的代码非常脆弱。

编辑:

标准中并非所有内容都是完美的。宏NULL是一个实现定义的c++空指针常量,与C NULL宏不完全兼容,除了类型隐藏隐式转换它在一个无用的和容易出错的工具。

NULL不是一个空指针,而是一个O/OL文字。

告诉我下一个例子不会让人困惑:

void foo(char *);
void foo(int);
foo(NULL); // calls int version instead of pointer version!

是不是因为这一切,在新标准中出现了std::nullptr_t

如果你不想等待新标准的出台,想要使用nullptr,至少要使用一个像Meyers建议的那样像样的nullptr(参见jonh comment)。

奇怪,没有人,包括Stroustroup提到过。虽然谈论了很多标准和美学,但没有人注意到使用0代替NULL危险的,例如,在架构的变量参数列表中,sizeof(int) != sizeof(void*)。像Stroustroup一样,出于美学原因,我更喜欢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)它声明了你的意图(不要让我搜索你所有的代码,试图找出一个变量是指针还是一些数字类型)。

2)在某些需要变量参数的API调用中,它们将使用null指针来指示参数列表的结束。在这种情况下,使用“0”而不是NULL可能会导致问题。在64位平台上,va_arg调用需要一个64位指针,但您将只传递一个32位整数。在我看来,你是在依靠其他32位来为你归零?我见过某些编译器(例如英特尔的icpc)不是那么友好——这导致了运行时错误。

将指针设置为0并不那么清楚。特别是如果你使用c++以外的语言。这包括C语言和Javascript。

我最近用这样的代码删除:

virtual void DrawTo(BITMAP *buffer) =0;

第一次为纯虚函数。我以为这只是一个星期的魔术表演。当我意识到它只是将函数指针设置为null(因为虚拟函数在大多数情况下只是c++的函数指针)时,我踢了自己。

virtual void DrawTo(BITMAP *buffer) =null;

如果我的新眼睛没有间隔的话就不会那么令人困惑了。实际上,我想知道为什么c++不使用小写null,就像它现在使用小写false和true一样。

使用0或NULL都有相同的效果。

然而,这并不意味着它们都是很好的编程实践。鉴于在性能上没有差异,选择低级感知选项而不是不可知论/抽象选项是一种糟糕的编程实践。帮助代码的读者理解您的思维过程

NULL, 0,0.0, '\0', 0x00和其他东西都转换为相同的东西,但在你的程序中是不同的逻辑实体。它们应该这样使用。NULL是指针,0是数量,0x0是位感兴趣的值,等等。无论指针是否编译,都不能将'\0'赋值给它。

我知道一些社区鼓励通过打破环境契约来展示对环境的深入了解。然而,负责任的程序员会编写可维护的代码,并将此类实践排除在他们的代码之外。

我主张在任何可能的情况下都不要使用0或NULL指针。

使用它们迟早会导致你的代码出现分段错误。根据我的经验,指针是c++中最大的bug来源之一

此外,它还会导致在整个代码中出现“if-not-null”语句。如果您可以依赖始终有效的状态,那就更好了。

几乎总是有更好的选择。

我想说,历史已经证明了这一点,那些主张使用0(零)的人是错误的(包括Bjarne Stroustrup)。支持0的理由主要是审美和“个人偏好”。

c++ 11创建后,使用新的nullptr类型,一些编译器开始抱怨(使用默认形参)将0传递给带有指针参数的函数,因为0不是指针。

如果代码是使用NULL编写的,那么可以通过代码库执行简单的搜索和替换,使其成为nullptr。如果您被使用0作为指针编写的代码所困扰,那么更新它将变得更加乏味。

如果你现在必须为c++ 03标准编写新代码(并且不能使用nullptr),你真的应该只使用NULL。这将使您将来更容易更新。