为什么 C++ 的 NULL 通常是整数文字而不是 C 中的指针?

Why is C++'s NULL typically an integer literal rather than a pointer like in C?

多年来我一直在编写 C++,对空指针使用 nullptr。我也知道 C,NULL 起源于此,请记住它是空指针的常量,类型为 void *.

出于某些原因,我不得不在我的 C++ 代码中使用 NULL。好吧,想象一下当在一些模板参数推导过程中编译器告诉我我的 NULL 真的是一个......长时我的惊讶。所以,我再次检查:

#include <type_traits>
#include <cstddef>

static_assert(not std::is_same<decltype(NULL), long>::value, "NULL is long ???");

确实,静态断言失败了(使用 GCC 和 Clang)。

我查看了 cppreference.com,果然(C++11 的措辞):

The macro NULL is an implementation-defined null pointer constant, which may be an integer literal with value zero, or a prvalue of type std::nullptr_t.

为什么这是有道理的?就其本身而言,并考虑到 C 的不兼容性?

在 C 中,void* 可以隐式转换为任何 T*。因此,将 NULL 设为 void* 是完全合适的。

但这非常危险。所以 C++ 取消了此类转换,要求您手动执行大多数指针转换。但这会造成与 C 的源代码不兼容;一个使用 NULL C 想要的方式的有效 C 程序将无法在 C++ 中编译。它还需要一堆冗余:T *pt = (T*)(NULL);,这会令人恼火且毫无意义。

因此 C++ 将 NULL 宏重新定义为整数文字 0。在 C 中,the literal 0 is also implicitly convertible to any pointer type 并生成空指针值,这是 C++ 保留的行为。

现在,当然,将文字 0(或更准确地说,值为 0 的整数常量表达式)用于空指针常量……不是最好的主意。特别是在允许重载的语言中。因此,C++11 完全放弃了使用 NULL 的关键字,该关键字专门表示“空指针常量”,仅此而已。

两种语言中,NULL一个实现定义的空指针常量。 C++ 部分 17.2.3,其定义参考了 C 7.19。

表示在C中,NULL可以定义为整数类型,也可以定义为void*类型,在C++中可以定义为整数类型;如果我正确解释了标准,它也可以定义为 nullptr_t。一个隐藏的(非规范的)脚注说 (void*)0 不能是一个有效的定义,这是有道理的,因为 C++ 没有 C 从 void* 到其他指针类型的隐式转换。

如果您有一个将其定义为 ((void*)0) 的 C 编译器和一个将其定义为 0L 的 C++ 编译器,它们都是一致的。两种实现都满足用例(可以从 NULL 分配和比较)。

C++ 引入 nullptr 主要是为了提供适合重载的类型化值,因为将 NULL 传递给函数可以 select 整数版本被认为令人惊讶。

我的假设一直是实现将 NULL 保持为 0 的决定是与 C++98 向后兼容的问题。我已经看到 lot 的代码在非指针上下文中使用 NULL,特别是作为(可能是无意的,或者至少是不知情的)替代数组中的空终止符.自 11 年以来的最佳实践是“根本不使用 NULL”,将 NULL 重新定义为 nullptr 可能会破坏 bad/old 代码,而对帮助 good/new 代码。

C 并不简单地将 NULL 定义为 (void *)0。也可以将其定义为 0 或任何计算结果为它的常量表达式。使用 #define NULL 0 在任何一种语言中都有效。

编辑:this answer非常好,也比较详细。

vcruntime.h

定义如下:

#ifdef __cplusplus
    #define NULL 0
#else
    #define NULL ((void *)0)