C预处理器是否删除了“&*”的实例?
我正在玩gcc
并尝试以下代码:
int A = 42; int *B = &A; int *C = &*B;
和C == &A
,如预期的那样。 但是当我尝试:
int *B = NULL; int *C = &*B;
原来C == NULL
,没有段错误。 所以&*B
在取得地址之前实际上并没有取消引用B
我的猜测是预处理器在它们甚至到达编译器之前就剥离了&*
和*&
实例,因为它们互相否定,但我找不到任何文档来validation这是标准C还是特定于编译器。
预处理器是否会剥离&*
和*&
,我可以从任何给定的编译器中获得这种行为吗?
这并没有被预处理器剥离,而且&*
最终只相当于指针本身,我们可以通过草拟C99标准 6.5.3.2
地址和间接操作符第4段来看到这一点,它说:
一元*运算符表示间接。 如果操作数指向函数,则结果是函数指示符; 如果它指向一个对象,则结果是指定该对象的左值。 如果操作数具有类型”指向类型’的指针,则结果具有类型”type”。 如果为指针分配了无效值,则unary *运算符的行为未定义。 87)
和脚注87说:
因此,&* E等效于E(即使E是空指针),[…]
第3段说( 强调我的 ):
一元&运算符产生其操作数的地址。 如果操作数具有类型”type”,则结果具有类型”指向类型”的指针。 如果操作数是一元*运算符的结果,则不会对该运算符和&运算符进行求值,结果就好像两者都被省略 ,除了对运算符的约束仍然适用且结果不是左值。
更新
值得注意的是,对于gcc
和clang
您可以使用-E
标志( 请参见实时 )和Visual Studio / EP ( 请参见实时 )查看预处理的结果。
此外,值得注意的是,正如MSalters在他的评论中所说,只有两个令牌&*
不足以理解上下文,正如他的例子所示:
int *p, *q ; int foo = *p & *q ;
因此,在预处理阶段甚至不能删除&*
因为您没有足够的信息来确定是否是运算符或按位运算符的地址 。
预处理器不会忽略&*
。 但是,C 2011标准在6.5.3.2 3中说,关于&
:
如果操作数[of]是一元*运算符的结果,则不会对该运算符和&运算符进行求值,结果就好像两者都被省略,除了对运算符的约束仍然适用且结果不是左值。
根据上述约束的要求, *的操作数必须具有指针类型。 因此, &*3
不会被本条改为3
; 它违反了约束条件,因为3
没有指针类型。 另外, &*x
没有完全改为x
,因为结果不是左值。 例如,这是不允许的:
int a, *x; x = &a; // Normal, allowed. &*x = &a; // Not allowed; `&*x` does not became exactly the same as `x`.