Sha*_*baz 18 c null-pointer language-lawyer
这可以被认为是这个问题的扩展(我只对C感兴趣,但添加C++来完成扩展)
6.3.2.3.3中的C11标准说:
值为0的整型常量表达式或此类表达式转换为类型
void *称为空指针常量.
我个人对此的看法是0并且(void *)0表示空指针,其整数值实际上可能不是0,但是不包括0强制转换为任何其他类型.
但是,标准然后继续:
如果将空指针常量转换为指针类型,则生成的指针称为空指针,...
它包含(int *)0为空指针,因为强制转换是一种显式转换(C11,6.3),它在转换方法下列出.
然而,令我惊讶的是以下短语
...或者这样的表达式转换为
void *...
有了上面的语义,这句话似乎完全没用.问题是,这句话完全没用吗?如果没有,它有什么影响?因此,是否(int *)0为空指针?
另一个可以帮助讨论的问题如下.被(long long)123视为"123转换为long long",或"123与类型long long".换句话说,有没有转换(long long)123?如果没有,则上面的第二个引用不包括(int *)0为空指针.
zwo*_*wol 31
简短回答:
在C和C++中,(int *)0是一个常量表达式,其值为空指针.但是,它不是空指针常量.我知道,constant-expression-which-value-is-null-pointer和null-pointer-constant之间唯一可观察到的区别是null-pointer-constant可以赋值给任何一个lvalue.指针类型,但是constant-expression-which-value-is-a-null-pointer具有特定的指针类型,并且只能分配给具有兼容类型的左值.在C中,但不是C++,(void *)0也是一个空指针常量; 这是void *与一般C-but-not-C++规则一致的特殊情况,该规则void *与任何其他指针到对象类型兼容.
例如:
long *a = 0; // ok, 0 is a null pointer constant
long *b = (long *)0; // ok, (long *)0 is a null pointer with appropriate type
long *c = (void *)0; // ok in C, invalid conversion in C++
long *d = (int *)0; // invalid conversion in both C and C++
Run Code Online (Sandbox Code Playgroud)
在这种情况下,即使在C中,空指针常量(void *)0与具有类型的constant-expression-which-value-is-a-null指针之间的差异void *也是可见的:
typedef void (*fp)(void); // any pointer-to-function type will show this effect
fp a = 0; // ok, null pointer constant
fp b = (void *)0; // ok in C, invalid conversion in C++
fp c = (void *)(void *)0; // invalid conversion in both C and C++
Run Code Online (Sandbox Code Playgroud)
此外,它现在没有实际意义,但是自从你提出它以来:无论long *空指针的位表示是什么,所有这些断言都表现为注释所示:
// 'x' is initialized to a null pointer
long *x = 0;
// 'y' is initialized to all-bits-zero, which may or may not be the
// representation of a null pointer; moreover, it might be a "trap
// representation", UB even to access
long *y;
memset(&y, 0, sizeof y);
assert (x == 0); // must succeed
assert (x == (long *)0); // must succeed
assert (x == (void *)0); // must succeed in C, unspecified behavior in C++
assert (x == (int *)0); // invalid comparison in both C and C++
assert (memcmp(&x, &y, sizeof y) == 0); // unspecified
assert (y == 0); // UNDEFINED BEHAVIOR: y may be a trap representation
assert (y == x); // UNDEFINED BEHAVIOR: y may be a trap representation
Run Code Online (Sandbox Code Playgroud)
"未指定"的比较不会引发未定义的行为,但标准并未说明它们是评估是真还是假,并且不需要实现来记录它们中的哪一个,或者甚至选择一个并坚持它.memcmp如果您多次调用它,则返回0和1之间的交替将完全有效.
标准报价的长答案:
要了解空指针常量是什么,首先必须了解整数常量表达式是什么,并且这非常多毛 - 完整的理解要求您详细阅读C99的6.5和6.6节.这是我的总结:
甲常量表达式是任何C的表达,编译器可以评估一个常数而无需知道任何对象的值(const或以其他方式;然而,enum值是公平的游戏),并且其具有无副作用.(这是大约25页标准的大幅简化,可能不准确.)
整数常量表达式是常量表达式的受限子集,可方便地在单个段落中定义,C99 6.6p6及其脚注:
整数常量表达式96应具有整数类型,并且只应具有整数常量的操作数,枚举常量,字符常量,
sizeof结果为整数常量的表达式,以及作为强制转换的直接操作数的浮点常量.整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof运算符的操作数的一部分.96整型常量表达式用于指定结构的位字段成员的大小,枚举常量的值,数组的大小或大小写常量的值.适用于[
#if]中使用的整数常量表达式的其他约束在6.10.1中讨论.
为了讨论的目的,重要的是
转换运算符...只能将算术类型转换为整数类型
这意味着(int *)0是不一个整数常量表达式,虽然这是一个常量表达式.
C++ 98定义似乎或多或少等价,模C++特性和与C的偏差.例如,C++中字符和布尔类型与整数类型的更强分离意味着C++标准说的是" 整数常量表达式"而不是" 整型常量表达式",然后有时不仅需要整型常量表达式,但在整数表达式整数类型,排除char,wchar_t以及bool(也许也signed char和unsigned char?这不是很清楚,我从文字).
现在,空指针常量的C99定义是这个问题的全部内容,所以我将重复它:6.3.2.3p3说
值为0的整型常量表达式或此类表达式转换为类型
void *称为空指针常量.如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较.
Standardese非常非常直观.这两句话的意思完全相同:
值为0的整型常量表达式称为空指针常量.
值为0的整数常量表达式,强制转换为类型void *,也是一个空指针常量.
当任何空指针常量转换为指针类型时,结果指针称为空指针,并保证比较不等于...
(斜体字-词的定义粗体-我的重点),那么这意味着什么,在C,(long *)0并(long *)(void *)0正在编写完全一样的东西,也就是空指针类型的两种方式long *.
C++是不同的.等效文本是C++ 98 4.10 [conv.ptr]:
甲空指针常数是整数表达式(5.19),该计算结果为零的整数类型的右值.
就这样."整数类型的整数常量表达式rvalue"与C99的"整数常量表达式"非常相似,但是有一些东西在C中有资格而不是C++:例如,在C中,字符文字'\x00'是一个整数常量表达式,因此是一个空指针常量,但在C++中它不是整数类型的整数常量表达式,因此它也不是空指针常量.
但更重要的是,C++没有"或者这样的表达式转换为void *"子句.这意味着,((void *)0)是不为空指针在C++中是恒定的.它仍然是一个空指针,但它不与任何其他指针类型兼容.这与C++的普遍挑剔型系统一致.
C++ 11(但不是,AFAIK,C11)修改了"空指针"的概念,为它们添加了一个特殊类型(nullptr_t)和一个新的关键字,它计算为空指针的常量(nullptr).我不完全理解这些变化,我不会尝试解释它们,但我很确定裸机0在C++ 11中仍然是一个有效的空指针常量.
Kei*_*son 10
评估表达式会(int*)0产生类型的空指针int*.
(int*)0不是空指针常量.
甲空指针常数是一种特定类型中可能出现的C源代码表达.甲空指针是在运行的程序中可能发生的一个值.
C和C++(两种不同的语言)在这方面的规则略有不同.C++没有"或者这样的表达式转换为类型void*"的措辞.但我认为这不会影响你问题的答案.
至于你的问题(long long)123,我不确定它是如何相关的,但是表达式123是类型的int,并且强制转换指定了转换int为long long.
我认为核心混淆是假设cast in (int*)0没有指定转换,因为0它已经是一个空指针常量.但是空指针常量不一定是指针类型的表达式.特别是,表达式0既是空指针常量又是类型表达式int; 它不是任何指针类型.术语空指针常量需要被视为单个概念,而不是一个短语,其含义取决于构成它的单个单词.