比较中 NULL 和零的区别

Difference Between NULL and Zero in Comparing

我对NULL略知一二,但是一说到比较就糊涂了。
例如:

int* p;
if(p == NULL){
//do stuff
}
if(p == 0){
//do stuff
}

在第一次比较中“p”与什么地址进行比较?

是否在寻找“p”的参考点,看是否有效?

NULL 在 C++ 编译器中只是一个定义 "null pointer constant"(通常值为 0)的宏。所以没有区别,除了 NULL 被用来表示一个意图(这很重要)。例如,您可以创建一个值为 NULLint 变量,它没有对标准声明 (int a = 0;).

进行任何特殊处理。

NULL 不是 "an empty space in memory"。它只是一个符号(通常)表示缺少某些东西(值、指针等...)。

但是,现在不鼓励在 C++ 中使用 NULL,应该使用更高级的 nullptr

在 C 的每个现代实现中,NULL 为零,通常作为指针值:

#define  NULL  (void *) 0

因此,比方说,将一个字符与 NULL 进行比较可能是无效的:

char ch = 'a';
if (ch == NULL)     //  probably "invalid comparison of pointer with scalar"

作为指针值,NULL 选择指向无效内存,因此取消引用它(在合适的体系结构上)将导致内存错误。大多数虚拟机仅为此目的保留较低内存,并通过将低内存未映射到物理内存来实现。有多少内存未保留?可能是几千字节,但许多实现保留几兆字节。

来自 C99 标准:

7.17 Common definitions <stddef.h>

3 The macros are

NULL

which expands to an implementation-defined null pointer constant; ...

来自 C++11 标准:

18.2 Types

3 The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).194

脚注 194:

194) Possible definitions include 0 and 0L, but not (void*)0.

Microsoft VS 2008 将其定义为:

/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

gcc/g++ 4.9.3 定义为:

#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL     /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else   /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else   /* C++ */
#define NULL 0
#endif  /* C++ */
#endif  /* G++ */
#endif  /* NULL not defined and <stddef.h> or need NULL.  */

我怀疑其他现代编译器也有类似的定义。

鉴于 NULL 的上述定义,

if(p == NULL){

扩展为:

if(p == ((void*)0) ){

在 C.

扩展为

if(p == 0){

在 C++ 中。

在其他 C++ 编译器中,该行可以扩展为

if(p == 0L){

使用 C++11 时,最好避免使用 NULL 并开始使用 nullptr

if ( p == nullptr ) {

从概念上讲,NULL 是指向任何地方的单数 pointer-value,并且可以隐式转换为任何 pointer-type。
实际上,不幸的是,你不能依赖它作为指针值,除非你在 pointer-only 上下文中使用它。

因此,在 C++11 和更高版本中分别使用 nullptr 向右转换 0 pointer-type,尤其是在整数零不会转换为指针的上下文中。

顺便说一句:虽然在大多数现代系统上,空指针实际上是 all-bits-zero,但标准并不要求它(可能有许多 bit-patterns 表示空指针,而 none all-zero),并且对空指针常量在源代码中的表示方式没有任何影响。


在 C++ 中:

The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).

定义为:

A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t.

Pre-C++11 最后一个选项明显不可用...
而post-C++11,因为不知道是什么,所以直接用nullptr


在 C:

The macros are NULL which expands to an implementation-defined null pointer constant; ...

定义为:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.

NULL 表示未被任何有效指针使用的值。因此,如果指针为 NULL,则它根本不指向任何变量。在指针上下文中,值零与 NULL 的含义相同,但是使用 NULL 比使用零更清楚。这就是您需要了解的有关 NULL 的全部信息。

know that NULL is a empty space in memory

不完全 - NULL 是 well-defined "nowhere" 不对应于任何有效的内存地址。

在 C 和 C++ 中,NULL 宏被定义为一个 空指针常量 ,这是一个 zero-valued 整数表达式。 C++ 还提供了 nullptr 字面值,它的计算结果也是空指针常量。当空指针常量出现在指针上下文中时,它将被转换为implementation-defined空指针。空指针值可能为也可能不是 0 值,但保证与任何有效指针值进行比较时不相等。

C 2011 online standard:

6.3.2.3 Pointers
...
3     An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
66)) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19

C++ 2014 online draft

2.13.7 Pointer literals [lex.nullptr]
    pointer-literal:
        nullptr

1     The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t. [Note: std::nullptr_t is a distinct type that is neither a pointer type nor a pointer to member type; rather, a prvalue of this type is a null pointer constant and can be converted to a null pointer value or null member pointer value. See 4.10 and 4.11. — end note ]

4.10 Pointer conversions [conv.ptr]
1     A null pointer constant is an integer literal (2.13.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4). A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t. [ Note: The resulting prvalue is not a null pointer value. — end note ]
...
18.2 Types [support.types]
...
3     The macro NULL is an implementation-defined C++ null pointer constant in this International Standard (4.10).194
194) Possible definitions include 0 and 0L, but not (void*)0

要敲定一些要点:

  1. NULL 宏、nullptr 文字(仅限 C++)和空指针 常量 始终为 0 值;
  2. 空指针不必为0值;
  3. 空指针永远不会等于有效的内存地址;
  4. 编译器的工作是将源代码中的空指针 constant 映射到生成的机器代码中的等效空指针 value ;作为程序员,您(通常)不需要担心实现中的实际空指针 value
  5. 由于空指针常量始终为 0 值,因此将指针值与 0 进行比较应该等同于将其与 NULLnullptr 进行比较。