在C中,NULL定义为(void *)0,而在C++中定义为0。为什么会这样呢?在C中,我可以理解如果NULL没有类型转换为(void *),那么编译器可能会/可能不会生成警告。除此之外,还有其他原因吗?
NULL
(void *)0
0
(void *)
new9mtju1#
回到C03,ISO规范(§4.10/1)将空指针定义为空指针常量是一个整型常量表达式(5.19),其值为零。这就是为什么在C中可以编写
int* ptr = 0;
在C语言中,这条规则是类似的,但有一点不同(参见6.3.2.3节):值为0的整型常量表达式,或转换为void *类型的表达式,称为空指针常量。55)如果空指针常量转换为指针类型,则生成的指针称为空指针,保证与指向任何对象或函数的指针不相等。因此,两者
void *
以及
int* ptr = (void *)0
是法律的的。但是,我的猜测是void*强制类型转换在这里,这样语句
void*
int x = NULL;
在大多数系统上都会产生编译器警告。在C++中,这是不法律的的,因为如果不进行强制转换,就不能隐式地将void*转换为另一个指针类型。例如,这是非法的:
int* ptr = (void*)0; // Legal C, illegal C++
然而,这会导致问题,因为代码
由于这个原因以及随之而来的混淆(以及另一种情况,稍后将介绍),从C++11开始,有一个关键字nullptr表示空指针:
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(int)
DoSomething(char*)
DoSomething(nullptr);
它将按预期调用DoSomething(char*)函数。类似地,假设我有一个vector<Object*>,并想将每个元素设置为空指针,使用std::fill算法,我可以尝试编写
vector<Object*>
std::fill
std::fill(v.begin(), v.end(), NULL);
但是,这并不能编译,因为模板系统将NULL视为int而不是指针。
int
std::fill(v.begin(), v.end(), (Object*)NULL);
这是丑陋的,有点违背了模板系统的目的。为了解决这个问题,我可以使用nullptr:
std::fill(v.begin(), v.end(), nullptr);
而且,由于已知nullptr具有对应于空指针的类型(具体地说,std::nullptr_t),因此这将正确地编译。
std::nullptr_t
hwazgwia2#
在C中,NULL扩展为实现定义的“空指针常量”。空指针常量是值为0的整数常量表达式,或者是转换为void*的表达式。因此,C实现可以将NULL定义为0或((void*)0)。在C中,空指针常量的规则是不同的。特别是,((void*)0)不是C空指针常量,因此C++实现不能那样定义NULL。
((void*)0)
9lowa7mx3#
C语言的产生是为了使微处理器的编程更容易。C指针用来存储内存中数据的地址。需要一种方法来表示指针没有有效值。选择地址零是因为所有微处理器都使用该地址来启动。由于它不能用于其他任何用途,零是表示指针没有有效值的一个好选择。C++是向后兼容C语言的,所以它继承了那个约定。当用作指针时强制转换为零的要求只是最近才增加的,后来的C语言希望有更严格的要求(希望有更少的错误),所以他们开始在语法上更加学究气。
3条答案
按热度按时间new9mtju1#
回到C03,ISO规范(§4.10/1)将空指针定义为
空指针常量是一个整型常量表达式(5.19),其值为零。
这就是为什么在C中可以编写
在C语言中,这条规则是类似的,但有一点不同(参见6.3.2.3节):
值为0的整型常量表达式,或转换为
void *
类型的表达式,称为空指针常量。55)如果空指针常量转换为指针类型,则生成的指针称为空指针,保证与指向任何对象或函数的指针不相等。因此,两者
以及
是法律的的。但是,我的猜测是
void*
强制类型转换在这里,这样语句在大多数系统上都会产生编译器警告。在C++中,这是不法律的的,因为如果不进行强制转换,就不能隐式地将
void*
转换为另一个指针类型。例如,这是非法的:然而,这会导致问题,因为代码
由于这个原因以及随之而来的混淆(以及另一种情况,稍后将介绍),从C++11开始,有一个关键字
nullptr
表示空指针:这不存在上述任何问题。
nullptr
相对于0的另一个优点是它更适合C++类型系统,例如,假设我有以下两个函数:如果我打电话
它相当于
它调用
DoSomething(int)
而不是预期的DoSomething(char*)
。但是,对于nullptr
,我可以写它将按预期调用
DoSomething(char*)
函数。类似地,假设我有一个
vector<Object*>
,并想将每个元素设置为空指针,使用std::fill
算法,我可以尝试编写但是,这并不能编译,因为模板系统将
NULL
视为int
而不是指针。这是丑陋的,有点违背了模板系统的目的。为了解决这个问题,我可以使用
nullptr
:而且,由于已知
nullptr
具有对应于空指针的类型(具体地说,std::nullptr_t
),因此这将正确地编译。hwazgwia2#
在C中,
NULL
扩展为实现定义的“空指针常量”。空指针常量是值为0的整数常量表达式,或者是转换为void*
的表达式。因此,C实现可以将NULL
定义为0
或((void*)0)
。在C中,空指针常量的规则是不同的。特别是,
((void*)0)
不是C空指针常量,因此C++实现不能那样定义NULL
。9lowa7mx3#
C语言的产生是为了使微处理器的编程更容易。C指针用来存储内存中数据的地址。需要一种方法来表示指针没有有效值。选择地址零是因为所有微处理器都使用该地址来启动。由于它不能用于其他任何用途,零是表示指针没有有效值的一个好选择。C++是向后兼容C语言的,所以它继承了那个约定。
当用作指针时强制转换为零的要求只是最近才增加的,后来的C语言希望有更严格的要求(希望有更少的错误),所以他们开始在语法上更加学究气。