在CNULL
中定义为,(void *)0
而在C ++中定义为0
。为什么会这样呢?在CI中可以理解,如果NULL
不进行类型转换,(void *)
则编译器可能会/可能不会生成警告。除此之外,还有什么原因吗?
Answers:
回到C ++ 03,ISO规范(§4.10/ 1)将空指针定义为
空指针常量是整数类型的整数常量表达式(5.19)rvalue,其值为零。
这就是为什么在C ++中您可以编写
int* ptr = 0;
在C中,此规则相似,但有些不同(第6.3.2.3/3节):
值为0的整数常量表达式,或将这种类型强制转换为type的表达式
void *
称为空指针常量。55)如果将空指针常量转换为指针类型,则可以保证所得的指针称为空指针。比较不等于指向任何对象或函数的指针。
因此,两者
int* ptr = 0;
和
int* ptr = (void *)0
是合法的。但是,我的猜测是void*
演员表在这里,这样的语句
int x = NULL;
在大多数系统上产生编译器警告。在C ++中,这是不合法的,因为您不能在没有强制转换的void*
情况下将a隐式转换为另一种指针类型。例如,这是非法的:
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
视为anint
而不是指针。为了解决这个问题,我必须写
std::fill(v.begin(), v.end(), (Object*)NULL);
这是丑陋的,并且在一定程度上破坏了模板系统的目的。要解决此问题,我可以使用nullptr
:
std::fill(v.begin(), v.end(), nullptr);
并且由于nullptr
已知其类型与空指针相对应(具体来说,std::nullptr_t
),因此可以正确编译。
希望这可以帮助!
0
可选值转换为的任何常量整数表达式void*
。
NULL
必须(void*)0
在C中。事实并非如此。不幸的是,它只能定义为任何空指针常量,因此在C语言中并不是一个非常可靠的概念。因此,我个人认为NULL
应该避免这样做。有些人似乎更喜欢它是指针类型的原因,更多是将隐式参数提升为没有原型的函数的规则,即va_arg参数列表。但这是另一个故事...
创建C语言是为了简化对微处理器的编程。AC指针用于将数据地址存储在内存中。需要一种方法来表示指针没有有效值。由于所有微处理器都使用该地址进行引导,因此选择了地址零。因为它不能用于其他任何事情,所以零表示一个没有有效值的指针是一个不错的选择。C ++向后兼容C,因此它继承了该约定。
用作指针时强制转换零的要求只是最近的补充。后来的C语言希望更加严格(希望错误更少),因此他们开始对语法更加学究。
0
为指针类型。C和C ++都没有这样的规则。在C语言中,您可能具有(void*)0
一个空指针常量,但是没有什么强迫您这样做。
0
source中的常量必须是一个空指针常量-但这并不要求空指针的内部表示形式必须全部为零,也不必与整数零的表示形式相同。
*(int*)0 == 0
。编写不假定空指针为全零位的代码确实没有那么困难。
void*
为任何指针类型,而在C ++中,则不能。