C预处理器是否删除了"&*"的实例?

eve*_*ode 25 c standards addressof indirection c-preprocessor

我正在玩,gcc并尝试了以下一些代码:

int A = 42;
int *B = &A;
int *C = &*B;
Run Code Online (Sandbox Code Playgroud)

并且C == &A,正如所料.但是当我尝试:

int *B = NULL;
int *C = &*B;
Run Code Online (Sandbox Code Playgroud)

原来C == NULL,没有段错误.因此,在获取其地址之前&*B实际上并未解除引用B.

我的猜测是预处理器剥离出来的情况下,&**&之前,他们甚至得到了编译器,因为他们否定对方,但我无法找到任何文件,以验证这是否是标准ç或编译器特定的.

被预处理器剥离出来&*,并*&和我可以期待从任何给定的编译器这种行为?

Sha*_*our 31

这不会被预处理器剥离,&*只是最终等同于指针本身,我们可以通过草拟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 ;
Run Code Online (Sandbox Code Playgroud)

因此&*,在预处理阶段甚至不可能删除,因为您没有足够的信息来确定运算符&地址还是按位和运算符.

  • 我想这回答了我的问题.答案是否定的,它没有被剥离:编译器本身认为它等同于指针.由于它在标准中,我们可以预期行为在编译器之间保持一致. (5认同)
  • 请记住,编译器在评估`*B`时,不知道它是*l值*还是*r值*,因此它假定为*l-value*,直到另有证明并返回B的值为止(没有解除引用).并且应用于*l-value*的`&`运算符将简单地返回由*l-value*表示的地址(作为*r-value*). (2认同)

Eri*_*hil 10

预处理器不会遗漏&*.但是,C 2011标准在6.5.3.2 3中说,关于&:

如果[的操作数& ]是一元的结果*操作,既没有操作者,也没有操作员进行评价,其结果是因为如果两者都省略,不同的是在运营商的限制仍然适用,且结果不是左值.

根据上述约束的要求,*的操作数必须具有指针类型.因此,本条款&*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`. 
Run Code Online (Sandbox Code Playgroud)