在C中,NULL
定义为(void *)0
,而在C ++中定义为0
。为什么会这样?
在C中我可以理解,如果NULL
不是(void *)
的类型转换,那么编译器可能会/可能不会生成警告。除此之外,有什么理由吗?
答案 0 :(得分:101)
回到C ++ 03中,空指针由ISO规范(§4.10/ 1)定义为
空指针常量是整数类型的整数常量表达式(5.19)rvalue,其值为零。
这就是为什么在C ++中你可以编写
int* ptr = 0;
在C中,这个规则是相似的,但有点不同(§6.3.2.3/ 3):
一个整数常量表达式,其值为0,或者这样的表达式强制转换为类型
void *
,称为空指针常量.55)如果将空指针常量转换为a 指针类型,结果指针,称为空指针,保证比较不等 指向任何对象或函数的指针。
因此,两者
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 ++。由于这一点以及随之而来的混淆(以及后面所示的另一种情况),从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
)对应的类型,因此将正确编译。
希望这有帮助!
答案 1 :(得分:16)
在C中,NULL
扩展为实现定义的“空指针常量”。空指针常量是值为0的整型常量表达式,或者是转换为void*
的表达式。因此,C实现可以将NULL
定义为0
或((void*)0)
。
在C ++中,空指针常量的规则是不同的。特别是,((void*)0)
不是C ++空指针常量,因此C ++实现无法以这种方式定义NULL
。
答案 2 :(得分:-6)
创建C语言是为了更容易编程微处理器。 C指针用于存储内存中的数据地址。需要一种方法来表示指针没有有效值。选择地址零,因为所有微处理器都使用该地址进行启动。由于它不能用于任何其他任何零是一个很好的选择来表示没有有效值的指针。 C ++向后兼容C,因此它继承了该约定。
当用作指针时,将零转换的要求仅是最近添加的。后来的C希望有更严格的(并且希望更少的错误),所以他们开始对语法更加迂腐。