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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7016861/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:22:04  来源:igfitidea点击:

Why are NULL pointers defined differently in C and C++?

c++cpointersnull

提问by mohit

In C, NULLis defined as (void *)0whereas in C++ it is 0. Why is it so? In C I can understand that if NULLis not typecast to (void *)then compilers may/may not generate warning. Other than this, is there any reason?

在 C 中,NULL被定义为,(void *)0而在 C++ 中,它是0. 为什么会这样?在 CI 中可以理解,如果NULL不是类型转换,(void *)那么编译器可能/可能不会生成警告。除此之外,还有什么原因吗?

回答by templatetypedef

Back in C++03, a null pointer was defined by the ISO specification (§4.10/1) as

在 C++03 中,ISO 规范(第 4.10/1 节)将空指针定义为

A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.

空指针常量是整数类型的整数常量表达式 (5.19) 右值,其计算结果为零。

This is why in C++ you can write

这就是为什么在 C++ 中你可以写

int* ptr = 0;

In C, this rule is similar, but is a bit different (§6.3.2.3/3):

在 C 中,此规则类似,但略有不同(第 6.3.2.3/3 节):

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.

值为 0 的整数常量表达式,或转换为 type 的此类表达式 void *,称为空指针常量。55) 如果将空指针常量转换为指针类型,则结果指针(称为空指针)保证为比较不等于指向任何对象或函数的指针。

Consequently, both

因此,两者

int* ptr = 0;

and

int* ptr = (void *)0

are legal. However, my guess is that the void*cast is here so that statements like

是合法的。然而,我的猜测是void*演员阵容在这里,所以像这样的陈述

int x = NULL;

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:

在大多数系统上产生编译器警告。在 C++ 中,这是不合法的,因为您不能在没有强制转换的void*情况下将 a 隐式转换为另一种指针类型。例如,这是非法的:

int* ptr = (void*)0; // Legal C, illegal C++

However, this leads to issues because the code

但是,这会导致问题,因为代码

int x = NULL;

is legal C++. Because of this and the ensuing confusion (and another case, shown later), since C++11, there is a keyword nullptrrepresenting a null pointer:

是合法的 C++。由于这一点和随之而来的混乱(以及另一种情况,稍后展示),从 C++11 开始,有一个关键字nullptr表示空指针:

int* ptr = nullptr;

This doesn't have any of the above problems.

这不存在上述任何问题。

The other advantage of nullptrover 0 is that it plays better with the C++ type system. For example, suppose I have these two functions:

nullptrover 0的另一个优点是它可以更好地与 C++ 类型系统配合使用。例如,假设我有这两个功能:

void DoSomething(int x);
void DoSomething(char* x);

If I call

如果我打电话

DoSomething(NULL);

It's equivalent to

它相当于

DoSomething(0);

which calls DoSomething(int)instead of the expected DoSomething(char*). However, with nullptr, I could write

它调用DoSomething(int)而不是预期的DoSomething(char*). 但是,有了nullptr,我可以写

DoSomething(nullptr);

And it will call the DoSomething(char*)function as expected.

它将DoSomething(char*)按预期调用该函数。

Similarly, suppose that I have a vector<Object*>and want to set each element to be a null pointer. Using the std::fillalgorithm, I might try writing

同样,假设我有一个vector<Object*>并且想要将每个元素设置为空指针。使用该std::fill算法,我可能会尝试编写

std::fill(v.begin(), v.end(), NULL);

However, this doesn't compile, because the template system treats NULLas an intand not a pointer. To fix this, I would have to write

但是,这不会编译,因为模板系统将其NULL视为int指针而不是指针。为了解决这个问题,我必须写

std::fill(v.begin(), v.end(), (Object*)NULL);

This is ugly and somewhat defeats the purpose of the template system. To fix this, I can use nullptr:

这很丑陋,并且在某种程度上违背了模板系统的目的。为了解决这个问题,我可以使用nullptr

std::fill(v.begin(), v.end(), nullptr);

And since nullptris known to have a type corresponding to a null pointer (specifically, std::nullptr_t), this will compile correctly.

并且由于nullptr已知具有对应于空指针的类型(特别是std::nullptr_t),这将正确编译。

Hope this helps!

希望这可以帮助!

回答by Keith Thompson

In C, NULLexpands to an implementation-defined "null pointer constant". A null pointer constant is either an integer constant expression with the value 0, or such an expression cast to void*. So a C implementation may define NULLeither as 0or as ((void*)0).

在 C 中,NULL扩展为实现定义的“空指针常量”。空指针常量要么是值为 0 的整数常量表达式,要么是转换为 的表达式void*。因此,C 实现可以定义NULLas0或 as ((void*)0)

In C++, the rules for null pointer constants are different. In particular, ((void*)0)is not a C++ null pointer constant, so a C++ implementation can't define NULLthat way.

在 C++ 中,空指针常量的规则是不同的。特别是,((void*)0)不是 C++ 空指针常量,因此 C++ 实现不能以NULL这种方式定义。

回答by Jay

The C language was created to make it easier to program microprocessors. A C pointer is used to store the address of data in memory. A way was needed to represent that a pointer had no valid value. The address zero was chosen since all microprocessors used that address for booting up. Since it couldn't be used for anything else zero was a good choice to represent a pointer with no valid value. C++ is backward compatible with C so it's inherited that convention.

创建 C 语言是为了更容易地对微处理器进行编程。AC指针用于存储数据在内存中的地址。需要一种方法来表示指针没有有效值。选择地址零是因为所有微处理器都使用该地址进行启动。因为它不能用于其他任何东西,所以零是表示没有有效值的指针的好选择。C++ 向后兼容 C,因此它继承了该约定。

The requirement of casting zero when used as a pointer is only a recent add on. Later generations of C wanted to have more rigor (and hopefully fewer errors) so they started being more pedantic about syntax.

用作指针时强制转换为零的要求只是最近的一个添加。后代的 C 想要更严格(希望错误更少),所以他们开始对语法更加迂腐。