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

moh*_*it 71 c c++ null pointers

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

tem*_*def 102

回到C++ 03中,空指针由ISO规范(§4.10/ 1)定义为

空指针常量是整数类型的整数常量表达式(5.19)rvalue,其值为零.

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

int* ptr = 0;
Run Code Online (Sandbox Code Playgroud)

在C中,此规则类似,但有点不同(§6.3.2.3/ 3):

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

因此,两者

int* ptr = 0;
Run Code Online (Sandbox Code Playgroud)

int* ptr = (void *)0
Run Code Online (Sandbox Code Playgroud)

是合法的.但是,我的猜测是,void*演员阵容就在这里,所以语句就像

int x = NULL;
Run Code Online (Sandbox Code Playgroud)

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

int* ptr = (void*)0; // Legal C, illegal C++
Run Code Online (Sandbox Code Playgroud)

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

int x = NULL;
Run Code Online (Sandbox Code Playgroud)

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

int* ptr = nullptr;
Run Code Online (Sandbox Code Playgroud)

这没有任何上述问题.

nullptr超过0 的另一个优点是它在C++类型系统中表现更好.例如,假设我有这两个函数:

void DoSomething(int x);
void DoSomething(char* x);
Run Code Online (Sandbox Code Playgroud)

如果我打电话

DoSomething(NULL);
Run Code Online (Sandbox Code Playgroud)

它相当于

DoSomething(0);
Run Code Online (Sandbox Code Playgroud)

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

DoSomething(nullptr);
Run Code Online (Sandbox Code Playgroud)

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

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

std::fill(v.begin(), v.end(), NULL);
Run Code Online (Sandbox Code Playgroud)

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

std::fill(v.begin(), v.end(), (Object*)NULL);
Run Code Online (Sandbox Code Playgroud)

这很丑陋,有点违背了模板系统的目的.要解决这个问题,我可以使用nullptr:

std::fill(v.begin(), v.end(), nullptr);
Run Code Online (Sandbox Code Playgroud)

并且因为nullptr已知有一个类型对应于空指针(具体而言std::nullptr_t),这将正确编译.

希望这可以帮助!

  • 看看@Keith Thompsons的回答.C中的"空指针常量"是值"0"的任何常量整数表达式,可选地强制转换为"void*". (3认同)
  • 几乎完美!只有一个单挑,你似乎仍然暗示在C中`NULL`必须是`(void*)0`.事实并非如此.不幸的是,它可能被定义为任何空指针常量,因此它在C中不是一个非常可靠的概念.因此我个人认为应该避免使用"NULL".并且有些人似乎更喜欢它是指针类型的原因更多是隐式参数提升到没有原型的函数的规则,即va_arg参数列表.但这是另一个故事...... (3认同)

Kei*_*son 17

在C中,NULL扩展为实现定义的"空指针常量".空指针常量是值为0的整型常量表达式,或者是这样的表达式void*.所以C实现可以定义NULL为as 0或as ((void*)0).

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