201

在 C++ 的早期,当它被固定在 C 之上时,您不能使用 NULL,因为它被定义为(void*)0. 您不能将 NULL 分配给除 之外的任何指针void*,这使得它毫无用处。在那些日子里,人们普遍认为您使用0(零)作为空指针。

时至今日,我继续使用零作为空指针,但我周围的人坚持使用NULL. NULL我个人认为将名称 ( ) 赋予现有值没有任何好处- 因为我也喜欢将指针测试为真值:

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

然后使用零更有意义(如果你使用NULL,你不能在逻辑上使用p && !q- 你需要明确比较NULL,除非你假设NULL为零,在这种情况下为什么使用NULL)。

是否有任何客观理由更喜欢零而不是 NULL(反之亦然),或者只是个人喜好?

编辑:我应该添加(并且最初是说)对于 RAII 和异常,我很少使用零/空指针,但有时你仍然需要它们。

4

21 回答 21

199

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

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

如果必须命名空指针,请调用它nullptr;这就是它在 C++11 中的名称。然后,nullptr将是一个关键字。

也就是说,不要为小事出汗。

于 2008-10-07T02:21:38.820 回答
126

我认为有一些论点(其中一个是相对较新的)与 Bjarne 的立场相矛盾。

  1. 意图文件

    UsingNULL允许对其使用进行搜索,并且它还强调了开发人员想要使用NULL指针,而不管编译器是否将其解释为NULL

  2. 指针和'int'的重载比较少见

    大家引用的例子是:

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

    然而,至少在我看来,上述问题不在于我们使用NULL空指针常量:而是我们有重载,foo()它们采用非常不同类型的参数。该参数必须是一个inttoo,因为任何其他类型都会导致模棱两可的调用,因此会生成有用的编译器警告。

  3. 分析工具今天可以提供帮助!

    即使在没有 C++0x 的情况下,今天也有可用的工具来验证哪些NULL是用于指针,哪些0是用于整数类型。

  4. C++ 11将有一个新std::nullptr_t类型。

    这是该表的最新论点。C++0x的问题0NULL正在积极解决,您可以保证对于每个提供 的实现NULL,他们要做的第一件事是:

     #define NULL  nullptr
    

    对于那些使用NULL而不是. 的人来说0,更改将是类型安全性的改进,只需很少或不付出任何努力 - 如果有的话,它也可能会在他们使用NULL的地方捕获一些错误0。对于0今天使用的任何人......好吧,希望他们对正则表达式有很好的了解......

于 2008-10-07T09:12:13.657 回答
47

使用 NULL。NULL 表明您的意图。它是 0 是一个无关紧要的实现细节。

于 2008-10-07T03:11:13.727 回答
42

我总是使用:

  • NULL用于指针
  • '\0'对于字符
  • 0.0用于花车和双打

其中 0 会很好。这是一个信号意图的问题。也就是说,我对此并不感兴趣。

于 2008-10-07T03:54:24.873 回答
34

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

在新项目中,我将其放在项目标题中:

static const int nullptr = 0;

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

于 2008-10-07T03:04:02.900 回答
22
    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 位为您清零?我见过一些不太友好的编译器(例如 Intel 的 icpc)——这导致了运行时错误。

于 2010-11-19T16:53:03.310 回答
17

如果我没记错的话,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而不是NULLnullptr_t这也是 a 的类型nullptr

于 2008-10-07T02:23:02.000 回答
16

我想说历史已经说话,那些主张使用 0(零)的人是错误的(包括 Bjarne Stroustrup)。支持 0 的论据主要是美学和“个人偏好”。

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

如果代码是使用 NULL 编写的,则可以通过代码库执行简单的搜索和替换以使其为 nullptr。如果您坚持使用选择 0 作为指针编写的代码,那么更新它会更加乏味。

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

于 2014-11-20T14:26:17.163 回答
11

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

char *p;

...

if (p) { ... }

不会像你期望的那样工作。你必须写

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

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

于 2008-10-07T02:22:23.263 回答
10

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

于 2008-10-07T02:21:38.820 回答
10

我通常使用 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”了解更多信息。

于 2009-03-31T07:30:11.910 回答
9

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

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

NULL, 0, 0.0, '\0', 0x00 和其他东西都翻译成同一个东西,但在你的程序中是不同的逻辑实体。它们应该这样使用。NULL 是一个指针,0 是数量,0x0 是一个值,其位是有趣的等等。无论它是否编译,您都不会将 '\0' 分配给指针。

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

于 2011-03-27T15:44:58.610 回答
5

奇怪的是,没有人,包括 Stroustroup 都提到过。虽然谈论了很多标准和美学,但没有人注意到代替 's 是危险,例如,在架构上的可变参数列表中。像 Stroustroup 一样,出于美学原因,我更喜欢它,但必须小心不要在其类型可能模棱两可的地方使用它。0NULLsizeof(int) != sizeof(void*)0

于 2009-09-17T07:24:37.117 回答
4

我尽量通过使用 C++ 引用来避免整个问题。而不是

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

你可能经常能写

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

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

于 2009-03-31T13:17:51.263 回答
3

我和 Stroustrup 一起讨论这个 :-) 因为 NULL 不是语言的一部分,所以我更喜欢使用 0。

于 2008-10-07T02:23:06.820 回答
3

主要是个人偏好,尽管可以提出 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,但这也归结为可读性。

于 2008-10-07T02:24:17.457 回答
3

我更喜欢使用 NULL,因为它清楚地表明您的意图是值表示指针而不是算术值。它是一个宏的事实是不幸的,但由于它是如此根深蒂固,所以几乎没有危险(除非有人做了一些非常愚蠢的事情)。我希望它从一开始就是一个关键字,但你能做什么?

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

C++09 将添加我认为早就应该的 nullptr 构造。

于 2008-10-07T02:52:00.287 回答
1

我总是使用 0。不是出于任何真正深思熟虑的原因,只是因为当我第一次学习 C++ 时,我读过一些推荐使用 0 的东西,而我一直都是这样做的。理论上,可读性可能存在混淆问题,但在实践中,我从未在数千工时和数百万行代码中遇到过这样的问题。正如 Stroustrup 所说,在标准变为 nullptr 之前,这实际上只是个人审美问题。

于 2008-10-07T02:51:28.683 回答
1

曾经有人告诉我...我将把 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 提出的像样的标准(参见 jon.h 评论)。

于 2009-08-05T16:36:53.077 回答
1

好吧,我主张尽可能不使用 0 或 NULL 指针。

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

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

几乎总是有更好的选择。

于 2013-07-10T08:34:08.187 回答
-4

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

我最近使用了一些类似这样的代码:

virtual void DrawTo(BITMAP *buffer) =0;

首次用于纯虚函数。我认为这是一个星期的魔法jiberjash。当我意识到它基本上只是将函数指针设置为 a null(因为虚拟函数在大多数情况下对于 C++ 来说只是函数指针)我踢了自己。

virtual void DrawTo(BITMAP *buffer) =null;

如果我的新眼睛没有适当的间距,那会比那个混蛋更容易混淆。实际上,我想知道为什么 C++ 不像null现在使用小写 false 和 true 那样使用小写。

于 2010-12-02T03:50:50.263 回答