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”,则结果具有类型”指向类型”的指针。 如果操作数是一元*运算符的结果,则不会对该运算符和&运算符进行求值,结果就好像两者都被省略 ,除了对运算符的约束仍然适用且结果不是左值。

更新

值得注意的是,对于gccclang您可以使用-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`.