为什么 NULL 指针在 C 和 C++ 中的定义不同?

2021-12-13 00:00:00 pointers 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.

希望这有帮助!

相关文章