我对地址运算符后跟取消引用运算符的行为有疑问。
我们来看看表达式&*p
,其中p
的类型为int *
。
C11标准(第6.5.3.2节)说:
一元 和 运算符产生其操作数的地址。如果操作数的类型为‘ 类型 ’, 结果的类型为“指向 类型 ’。如果操作数是一元运算的结果 * 操作员, 那个操作员和 和 对运算符进行评估,结果就像两个 除了对运算符的约束仍然适用并且结果不是左值之外,省略了该值。
带有脚注:
因此,&* E等效于E(即使E是空指针),而&(E1 [E2])等于((E1)+(E2))。如果E是函数指定符或左值是一元&运算符的有效操作数,则始终是正确的,*&E是函数指定符或等于E的左值。如果* P是左值并且T是以下项的名称一个对象指针类型,*(T)P是一个左值,其类型与T指向的类型兼容。一元*运算符用于取消对指针的引用的无效值包括空指针,针对所指向对象的类型不适当地对齐的地址以及对象生命周期结束后的地址。
很明显&*p
必须等于p
,除了&*p
不是左值。
如果我们现在考虑a
类型为int[10]
的{{1}}是什么类型?
例如&*a
和sizeof a
之间应该有区别吗?
一方面,如果我们评估sizeof &*a
,则&*a
会因解引用运算符而衰减为a
,它将变为int *
,而地址运算符则变为{ {1}}。
另一方面,如果int
表现为“好像都被省略了”,则类型应为int *
。
简短的example表明gcc对表达式的处理不同:
&*a
输出:
int[10]
这是否符合C11标准?
也许是因为“运算符上的约束仍然适用”并且取消引用运算符的操作数必须是指针吗?
答案 0 :(得分:13)
请考虑从数组到指针到第一元素的指针的转换分别发生并且在应用*
之前进行。尽管直到C实现确定是sizeof
还是&
的操作数(根据C 2018 6.3.2.1 3)才决定是否将数组转换为指针。不属于*
操作的一部分。因此,在我们检查&*
时,操作数必须已经是一个指针。
此外,对*
运算符的操作数的约束是它必须具有指针类型(C 2018 6.5.3.2 2)。因此,操作数必须是指针,而不是数组。
“结果好像都被省略了”这样的措辞促使我们考虑如果两个都被省略了,那么结果将是什么,但是案文继续说“除了对运算符的约束仍然适用并且结果是由于约束仍然适用,因此操作数必须是指针;在逻辑上不能施加约束并且操作数可能是尚未转换为指针的数组。