NULL宏实际上可以是nullptr吗?

43
根据标准N4713(7.11/1)的草案:
空指针常量是一个整数字面值(5.13.2),其值为零,或者是类型为std :: nullptr_t的prvalue。
和21.2.3 / 2:
宏NULL是一个实现定义的空指针常量。
因此可以将NULL定义为nullptr。cppreference上也提到了这一点:
#define NULL 0
//since C++11
#define NULL nullptr

同时,“加法运算符”条款表示(8.5.6/7):
如果将值0添加到或从空指针值中减去,则结果是空指针值。如果两个空指针值相减,则结果与转换为类型std :: ptrdiff_t的值0相等。
因此,以下代码应该是有效的:
0 + nullptr; 
nullptr - nullptr; 

但是由于std::nullptr_t缺少+/-运算符,所以代码无效

我有没有考虑到什么,或者NULL宏实际上不能定义为nullptr


1
是的,它可以。[[[[[[[[[[ - Cheers and hth. - Alf
8
空指针的 和空指针的 常量 是两个非常不同的概念。 - n. m.
@n.m:指针、nullptr_t和字面零之间的区别很重要。但是考虑到“或类型为std :: nullptr_t的prvalue”,您是否认为prvalue不是一个值?那是荒谬的。 - Cheers and hth. - Alf
5
它是一个“值”,但不是“空指针值”。 - Angew is no longer proud of SO
1
当然,它是一个值,类型为std::nullptr_t,它不是指针类型,因此没有基础来称其为“空指针值”(它根本不是指针值)。无论如何,“加法运算符”条款列出了可能参与加法运算符的类型,而std::nullptr_t不是其中之一,因此无论您是否将std::nullptr称为“空指针值”,std::nullptr - std::nullptr都是无效的。 - n. m.
显示剩余4条评论
4个回答

50

虽然 nullptr 是空指针常量,但它不是空指针。后者是某个指针类型的值,而 std::nullptr_t 不是。

参考:

空指针常量是一个整数字面值(5.13.2)且其值为零,或者是类型为 std::nullptr_t 的 prvalue。空指针常量可以转换为指针类型;结果是该类型的空指针值,并可与每种对象指针或函数指针类型的所有其他值区分开。这种转换称为空指针转换。[...]

N4659 中的 7.11/1,强调为我所加

因此,NULL 确实可以是没有提供算术运算符的 nullptr


6
@Cheersandhth.-Alf:“不,他应该得到一个赞,因为标准文本将“空指针值”视为术语而非仅仅是“值”。如果你想挖掘过去的冲突,那么你就不要责怪别人变得个人化。” - StoryTeller - Unslander Monica
2
抱歉,我无法理解为什么“nullptr本身不是指针值或指针。因此,算术运算不适用于nullptr”是正确的,如果“它不是空指针值”是错误的话。 - Baum mit Augen
2
@Cheersandhth.-Alf C++17 7.11/1:“空指针常量是一个整数字面值(5.13.2),其值为零或类型为std::nullptr_t的prvalue。空指针常量可以转换为指针类型;结果是该类型的空指针值,并且可与对象指针或函数指针类型的每个其他值区分开来。这样的转换称为空指针转换。”这似乎非常明确地表明nullptr(或任何其他类型为std::nullptr_t的prvalue)不是“空指针值”。 - Angew is no longer proud of SO
2
@Cheersandhth.-Alf 不管它是不是一个值,但哪里说它是一个空指针值? - Baum mit Augen
3
我需要一双新眼睛。抱歉造成困惑! - Cheers and hth. - Alf
显示剩余9条评论

9

nullptr是一个空指针字面量,虽然将nullptr转换为指针类型的结果是空指针值,但nullptr本身不属于指针类型,而是属于std::nullptr_t类型。如果您将nullptr转换为指针类型,则算术运算可行:

0 + (int*)nullptr; 
(int*)nullptr - (int*)nullptr;

NULL宏实际上可以是nullptr吗?

可以,因为nullptr是一个空指针字面量。

需要注意的是,在C++11之前,所有的空指针字面量在C++中也都是整型字面量,所以这种不好的代码:char c = NULL; 在实践中也能正常工作。如果NULL被定义为nullptr,那么这段代码将不再起作用。


6
关键字nullptr表示指针字面量。它是类型为std::nullptr_tprvalue。存在从nullptr到任何指针类型和任何成员指针类型的空指针值的隐式转换。 nullptr本身不是指针值或指针。因此,不能对nullptr进行算术运算。

所以8.5.6/7不适用于nullptr,因为它不是一个空指针值?(在阅读Baum的答案后删除了此评论,并在阅读该答案下面的讨论后重新发布;)) - 463035818_is_not_a_number
如果nullptrstd::nullptr_t类型,而不是指针类型,那么它如何成为指针字面量?您可能需要考虑重新表述以使其更准确。 - StoryTeller - Unslander Monica
@user463035818 是的,你说得对。prvalue(“pure” rvalue)是一个不是xvalue的rvalue。(例如:调用返回类型不是引用的函数的结果是prvalue)- 摘自这里 https://dev59.com/QnA65IYBdhLWcg3w1SfU - 273K
我不认为你理解我的目标。Literals是类型化的值。由于nullptr_t不是指针类型,因此nullptr不能成为指针字面量。 - StoryTeller - Unslander Monica
@user2079303 - 好吧,与其他prvalue字面值的一致性就这样破灭了。它不是“指针类型”,而是“指针字面值”!?真是见鬼了。 - StoryTeller - Unslander Monica
显示剩余2条评论

6
对于加法运算,两个操作数必须具有算术或未作用域枚举类型之一,或者一个操作数必须是完全定义的对象类型的指针,另一个则必须具有整数或未作用域枚举类型。
对于减法运算,以下情况之一必须成立:
(2.1) 两个操作数具有算术或未作用域枚举类型;或
(2.2) 两个操作数都是 cv-qualified 或 cv-unqualified 的相同完全定义对象类型的指针;或
(2.3) 左操作数是完全定义的对象类型的指针,右操作数具有整数或未作用域枚举类型。
因此,std::nullptr_t 不属于上述任何一种类型,所以 std::nullptr 不能参与加性运算。
需要注意的是,并非所有指针值都可以参与运算。例如,函数指针值和 void 指针值都不能参与运算,即使其中任意一个都是空指针值。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接