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

inn6fuwd  于 2022-12-24  发布在  其他
关注(0)|答案(3)|浏览(161)

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

new9mtju

new9mtju1#

回到C03,ISO规范(§4.10/1)将空指针定义为
空指针常量是一个整型常量表达式(5.19),其值为零。
这就是为什么在C
中可以编写

int* ptr = 0;

在C语言中,这条规则是类似的,但有一点不同(参见6.3.2.3节):
值为0的整型常量表达式,或转换为void *类型的表达式,称为空指针常量。55)如果空指针常量转换为指针类型,则生成的指针称为空指针,保证与指向任何对象或函数的指针不相等。
因此,两者

int* ptr = 0;

以及

int* ptr = (void *)0

是法律的的。但是,我的猜测是void*强制类型转换在这里,这样语句

int x = NULL;

在大多数系统上都会产生编译器警告。在C++中,这是不法律的的,因为如果不进行强制转换,就不能隐式地将void*转换为另一个指针类型。例如,这是非法的:

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

然而,这会导致问题,因为代码

int x = NULL;

由于这个原因以及随之而来的混淆(以及另一种情况,稍后将介绍),从C++11开始,有一个关键字nullptr表示空指针:

int* ptr = nullptr;

这不存在上述任何问题。
nullptr相对于0的另一个优点是它更适合C++类型系统,例如,假设我有以下两个函数:

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

如果我打电话

DoSomething(NULL);

它相当于

DoSomething(0);

它调用DoSomething(int)而不是预期的DoSomething(char*)。但是,对于nullptr,我可以写

DoSomething(nullptr);

它将按预期调用DoSomething(char*)函数。
类似地,假设我有一个vector<Object*>,并想将每个元素设置为空指针,使用std::fill算法,我可以尝试编写

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

但是,这并不能编译,因为模板系统将NULL视为int而不是指针。

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

这是丑陋的,有点违背了模板系统的目的。为了解决这个问题,我可以使用nullptr

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

而且,由于已知nullptr具有对应于空指针的类型(具体地说,std::nullptr_t),因此这将正确地编译。

hwazgwia

hwazgwia2#

在C中,NULL扩展为实现定义的“空指针常量”。空指针常量是值为0的整数常量表达式,或者是转换为void*的表达式。因此,C实现可以将NULL定义为0((void*)0)
在C中,空指针常量的规则是不同的。特别是,((void*)0)不是C空指针常量,因此C++实现不能那样定义NULL

9lowa7mx

9lowa7mx3#

C语言的产生是为了使微处理器的编程更容易。C指针用来存储内存中数据的地址。需要一种方法来表示指针没有有效值。选择地址零是因为所有微处理器都使用该地址来启动。由于它不能用于其他任何用途,零是表示指针没有有效值的一个好选择。C++是向后兼容C语言的,所以它继承了那个约定。
当用作指针时强制转换为零的要求只是最近才增加的,后来的C语言希望有更严格的要求(希望有更少的错误),所以他们开始在语法上更加学究气。

相关问题