为什么不将nullptr称为NULL?
为什么不将nullptr
称为NULL
?
在历史上,NULL
被定义为0,没有进行强制类型转换,编译器会忽略将数字强制转换为指针的警告。这导致以下代码是合法的:
void* p = 0;
但以下代码是不合法的,因为没有隐式类型转换:
void* p = 1234;
这样做的副作用是,NULL
可以被误用为数字值,正如其他回答中提到的那样。
为了改进这一点,引入了nullptr
,它强制将其视为指针,不能将其赋值给整数。
由于行为发生了改变,为了向后兼容,引入了一个新的名称。
还需要注意的是,nullptr
由编译器处理,其实际值不会暴露给用户(就像NULL
中的零一样)。这样可以更容易地使用与体系结构相关的值,比如0xdeadbeef
,而不会影响程序员的代码逻辑。
现在我饿了,想要一些"dead beef"。
0xfeedface 0xdeadbeef? 0xfeedface 0xcafef00d!(我们曾经有一个带有4位十六进制显示器的系统,整个团队的每个人几乎都知道包含字符a、b、c、d、e、f、i和o的几乎所有4个字母的单词,并用它们来互相交流。)
为什么不将nullptr称为NULL?
在C++中,nullptr是指针类型,而NULL往往被视为整数,有时在重载函数中,您需要明确使用指针而不是整数 - 这就是nullptr的用途。
所以要真正回答你的问题,NULL和nullptr有着不同的用途,重新定义其中一个为另一个可能会破坏已存在的代码库中的很多东西。
此外,请参考Bjarne Stroustrup的网站上的这个问题:
“我应该使用NULL还是0?”
在C++中,NULL的定义是0,所以只是美学上的差异。我喜欢避免使用宏,所以我使用0。NULL的另一个问题是,人们有时错误地认为它与0不同和/或不是整数。在早期的标准之前,NULL有时被定义为不合适的内容,因此必须避免使用。这在现在已经不太常见了。如果你必须给空指针命名,就称它为nullptr;这是C++11中的称呼。然后,“nullptr”将成为一个关键字。
但这就是问题 - 为什么不将NULL更改为nullptr呢?
因为您不能将int类型的变量(仅仅是一个例子)初始化为指针类型NULL(也就是nullptr),这将是一个很大的问题。
从技术上讲,nullptr不是指针类型,而是nullptr_t类型。
对,我只是试图澄清概念,也许你应该编辑答案来包含这一点。
就我个人而言,我认为NULL和nullptr具有相同的用途 - 至少在编写良好的代码中是如此。
为什么不将nullptr称为NULL?
在C++标准委员会成员Stephan T. Lavavej的一次演讲中,他解释说,尽管实现允许#define NULL nullptr,但这将破坏许多使用情况,比如int i = NULL;,而且显然有很多这样的情况。所以他们不能强制进行更改。
我希望他们至少会废弃这个用法,这样以后就可以将NULL定义为nullptr...(或者将nullptr称为NULL,然后nullptr_t可以具有弃用的转换为int)
嗯,这不能保证工作,至少在C++11之后不能保证。参考此处。因此,像int i = NULL;这样的写法是“不可移植的”。据我所知,在所有实现中都可以工作,但是,它不需要工作,所以它已经不止废弃了。
对于类似于int的情况,我偶尔会遇到一些代码,其中有人用str[end_pos] = NULL;来“以空值终止”他们的字符串。
int i = NULL;是一直都很邪恶。你为什么要这样做呢?
我认为Stephan T. Lavavej指的是在(nullptr在(drafts of) C++11中已经被引入之后定义NULL为nullptr。然而,在引入nullptr的N1601中也出现了类似的原理。
嗯,C在这方面有点邪恶。这就像使用str[end_pos] = NULL或str[end_pos] = 0,或者使用13代替\r,例如-常常使用。类型在C中并不重要...另一个例子是被广泛误用的long,特别是与将指针常规强制转换为int或long的方式相结合时。“发明”int i = NULL的人可能认为这是一种非常明显的方式来说“现在int i被初始化为默认值”。这很令人难过,但是C中有很多类似的实践。
不要把C带进来。str[end_pos] = NULL和int i = NULL只有在C++中才能保证有效。(C实际上并没有指定NULL的定义,但在任何合理的实现中它都不是int;只有在C++中,NULL被要求是一个整数。)
C允许将NULL定义为((void*) 0),并且已经使int i = NULL在技术上非法。
大多数情况下是正确的。但是我在谷歌上找到的第一件事就是这个,它将NULL定义为#define NULL 0,并警告不要在指针以外的任何地方使用它。不幸的是,我很确定很多人倾向于简单地复制这样的代码而不阅读文本,并开始将其作为常规做法使用。更加不幸的是,它实际上符合C99规范-“值为0的整数常量表达式,或该表达式转换为void*类型,被称为null指针常量。”(void*)0当然是更好的选择。
“int i = NULL [is] only guaranteed to be valid in C++...NULL [is] not an int in any sane implementation”-GCC 5.1即使在-Wall -Wextra -pedantic -ansi下也不会对int i = NULL抱怨。但是你是对的,NULL被定义为((void *)0)。然而,似乎仍然允许将空指针自动转换为0整数(甚至在CERT安全编码标准中都明确允许)。
我认为打破这种极其错误的行为是可以接受的。开发人员不应该被允许编写愚蠢的代码,只是因为它可以运行 😉
.R.Leggiero嗯,不要忘记大多数代码都是按计划编写的。在破坏用户代码之前,您只能走得这么远,否则人们将停止使用您的产品。
.M这从来都不是标准符合的,NULL也可以是0L,这会导致您的代码存在歧义。
然后C++11将变得像D一样-它比老的C++更好,但没有人使用它。一些公司需要依赖于30年前的代码库来进行日常业务,你知道吗?
nah,它会像Swift一样。Swift在每个版本更新中都会破坏代码,但这是为了更大的利益,并且他们提供了迁移工具来更新您的代码。现有的已编译二进制文件不会被破坏,您仍然可以使用旧的编译器编译旧代码。这才是正确的做法!
Swift怎么能和C++相提并论呢?它不是一种成熟的语言,所以没人指望它稳定,并且它的复杂性要小得多,这使得自动更新代码成为可能。
它们非常相似,因为它们都编译成汇编语言,它们都在不断发展,它们可以互相兼容,并且它们都致力于成为一种非常广泛使用的语言。此外,尽管Swift在表面上似乎更简单,但实际上它可以像C++一样做任何事情,只是方式不同。
所以C++为了解决他们通过将NULL定义为0而引起的问题,创建了nullptr,从而不必要地增加了C++的复杂性。
根据另一个回答指出,C++11并不要求将NULL定义为整数常量。它可以被定义为nullptr,但没有被要求这样做。符合C++11的实现可以“破坏”在非指针上下文中使用NULL的极度混乱的代码。主流实现选择不这样做,是因为旧代码库中存在这样的垃圾,而且ISO C++故意给了它们这个选择。