为什么 NULL 指针在 C 和 C++ 中的定义不同?
在 C 中,NULL
被定义为 (void *)0
而在 C++ 中它是 0
.为什么会这样?在 C 中,我可以理解如果 NULL
没有被类型转换为 (void *)
那么编译器可能会/可能不会产生警告.除此之外,还有什么原因吗?
In C, NULL
is defined as (void *)0
whereas in C++ it is 0
. Why is it so?
In C I can understand that if NULL
is not typecast to (void *)
then compilers may/may not generate warning. Other than this, is there any reason?
推荐答案
早在 C++03 中,空指针被 ISO 规范 (§4.10/1) 定义为
Back in C++03, a null pointer was defined by the ISO specification (§4.10/1) as
空指针常量是求值为零的整数类型的整数常量表达式 (5.19) 右值.
A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.
这就是为什么在 C++ 中你可以写
This is why in C++ you can write
int* ptr = 0;
在 C 中,此规则类似,但略有不同 (§6.3.2.3/3):
In C, this rule is similar, but is a bit different (§6.3.2.3/3):
值为 0 的整数常量表达式,或这样的表达式转换为类型void *
,称为空指针常量.55) 如果将空指针常量转换为指针类型,结果指针,称为空指针,保证比较不相等指向任何对象或函数的指针.
An integer constant expression with the value 0, or such an expression cast to type
void *
, is called a null pointer constant.55) 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.
因此,两者
int* ptr = 0;
和
int* ptr = (void *)0
是合法的.但是,我的猜测是 void*
演员表在这里,所以像
are legal. However, my guess is that the void*
cast is here so that statements like
int x = NULL;
在大多数系统上产生编译器警告.在 C++ 中,这是不合法的,因为您不能在没有强制转换的情况下将 void*
隐式转换为另一种指针类型.例如,这是非法的:
produce a compiler warning on most systems. In C++, this wouldn't be legal because you can't implicitly convert a void*
to another pointer type implicitly without a cast. For example, this is illegal:
int* ptr = (void*)0; // Legal C, illegal C++
然而,这会导致问题,因为代码
However, this leads to issues because the code
int x = NULL;
是合法的 C++.由于这一点以及随之而来的混乱(以及另一种情况,稍后显示),从 C++11 开始,就有一个关键字 nullptr
表示空指针:
is legal C++. Because of this and the ensuing confusion (and another case, shown later), since C++11, there is a keyword nullptr
representing a null pointer:
int* ptr = nullptr;
这没有任何上述问题.
nullptr
比 0 的另一个优点是它在 C++ 类型系统中表现得更好.例如,假设我有这两个功能:
The other advantage of nullptr
over 0 is that it plays better with the C++ type system. For example, suppose I have these two functions:
void DoSomething(int x);
void DoSomething(char* x);
如果我打电话
DoSomething(NULL);
相当于
DoSomething(0);
调用 DoSomething(int)
而不是预期的 DoSomething(char*)
.但是,使用 nullptr
,我可以写
which calls DoSomething(int)
instead of the expected DoSomething(char*)
. However, with nullptr
, I could write
DoSomething(nullptr);
它会按预期调用 DoSomething(char*)
函数.
And it will call the DoSomething(char*)
function as expected.
同样,假设我有一个 vector
并且想要将每个元素设置为空指针.使用 std::fill
算法,我可能会尝试编写
Similarly, suppose that I have a vector<Object*>
and want to set each element to be a null pointer. Using the std::fill
algorithm, I might try writing
std::fill(v.begin(), v.end(), NULL);
然而,这不会编译,因为模板系统将 NULL
视为 int
而不是指针.为了解决这个问题,我必须写
However, this doesn't compile, because the template system treats NULL
as an int
and not a pointer. To fix this, I would have to write
std::fill(v.begin(), v.end(), (Object*)NULL);
这很丑陋,并且在某种程度上违背了模板系统的目的.为了解决这个问题,我可以使用 nullptr
:
This is ugly and somewhat defeats the purpose of the template system. To fix this, I can use nullptr
:
std::fill(v.begin(), v.end(), nullptr);
并且由于已知 nullptr
具有对应于空指针的类型(具体来说,std::nullptr_t
),这将正确编译.
And since nullptr
is known to have a type corresponding to a null pointer (specifically, std::nullptr_t
), this will compile correctly.
希望这有帮助!
相关文章