为什么在C和C ++中定义的NULL指针是不同的?
在C中, NULL
被定义为(void *)0
而在C ++中则为0
。 为什么这样? 在CI中可以理解,如果NULL
不是types转换(void *)
那么编译器可能会/不会生成警告。 除此之外,有什么理由吗?
回到C ++ 03,一个空指针被ISO规范(§4.10/ 1)定义为
空指针常量是整数types的整数常量expression式(5.19)右值,其值为零。
这就是为什么在C ++中可以编写的原因
int* ptr = 0;
在C中,这个规则是相似的,但有点不同(§6.3.2.3/ 3):
一个整数常量expression式的值为0,或者被转换为
void *
types的expression式被称为空指针常量。如果空指针常量被转换为指针types,那么称为空指针的结果指针是保证比较不等于指向任何对象或函数的指针。
因此,两者
int* ptr = 0;
和
int* ptr = (void *)0
是合法的。 不过,我的猜测是void*
cast在这里是这样的陈述
int x = NULL;
在大多数系统上产生编译器警告。 在C ++中,这是不合法的,因为您不能隐式地将void*
隐式转换为另一种指针types,而无需强制转换。 例如,这是非法的:
int* ptr = (void*)0; // Legal C, illegal C++
但是,这会导致问题,因为代码
int x = NULL;
是合法的C ++。 由于这一点以及随之而来的混淆(以及后面显示的另一种情况),自从C ++ 11以来,有一个关键字nullptr
代表一个空指针:
int* ptr = nullptr;
这没有任何上述问题。
nullptr
超过0的另一个优点是它在C ++types的系统中performance更好。 例如,假设我有这两个function:
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
algorithm,我可能会尝试写入
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
具有对应于空指针的types(特别是std::nullptr_t
),所以这将正确编译。
希望这可以帮助!
在C中, NULL
扩展为一个实现定义的“空指针常量”。 空指针常量可以是值为0的整数常量expression式,也可以是将这种expression式转换为void*
。 所以C实现可以将NULL
定义为0
或者((void*)0)
。
在C ++中,空指针常量的规则是不同的。 特别是((void*)0)
不是C ++空指针常量,因此C ++实现不能以这种方式定义NULL
。
C语言的创build使编程微处理器变得更容易。 AC指针用于存储内存中的数据地址。 需要一种方式来表示一个指针没有有效的值。 因为所有微处理器都使用该地址来启动,所以select地址零。 由于它不能用于其他任何事情,所以用零表示没有有效值的指针是个不错的select。 C ++向后兼容C,所以它inheritance了这个约定。
当用作指针时,铸造零的需求只是最近添加的。 后来的C想要更严格(希望更less的错误),所以他们开始对语法更迂腐了。