【问题标题】:Is a.b always (&a)->b?a.b 总是 (&a)->b 吗?
【发布时间】:2020-07-05 23:39:53
【问题描述】:

在 C 中,a.b 通常是 (&a)->b 的同义词。

即使a 是一些杂乱复合词的宏,在所有情况下都是这样吗?或者在任何版本的 C 中是否存在等价不成立的边缘情况?

【问题讨论】:

  • 您可能打算询问(a).b(&(a))->b。否则,a 很容易成为一个表达式/宏,这样优先级会干扰运算符。
  • 等价是这样的:符号p->m(*p).m 的简写。基本等价不涉及&;这是您可以从中得出的东西,但失去了一般性:与& 的派生等价在& 不可接受的情况下不成立。

标签: c pointers language-lawyer


【解决方案1】:

这里是三个反例,都是基于应用&的约束:

  • a 是一个右值,因为它是一个函数返回的结构:
    int bar(void)
    {
        extern struct S { int b; } foo(void);
        return (&foo())->b;
    }
    
    Clang 说“错误:不能获取 'struct S' 类型的右值的地址”。但它接受return foo().b;
  • a 是一个右值,因为它是赋值的结果:
      int bar(void)
      {
          struct S { int b; } x = {0};
          struct S y;
          return (&(y=x))->b;
      }
    
    
    Clang 说“错误:不能获取 'struct S' 类型的右值的地址”。但它接受return (y=x).b;
  • a 被声明为register,所以它的地址可能不会被占用:
    int bar(void)
    {
        register struct S { int b; } a = {0};
        return (&a)->b;
    }
    
    Clang 说“错误:请求的寄存器变量地址”。

【讨论】:

    【解决方案2】:

    a.b 中,a 不需要是左值。

    例如,如果a 是扩展为函数调用的宏,则(&a)->b 是违反约束的。

    【讨论】:

      【解决方案3】:

      在 C 中,a.b 通常是 (&a)->b 的同义词。

      C11 标准中没有任何内容要求在所有情况下都必须具有这种等效性。相关部分 (5.5.2.3 Structure and union members) 实际上对它们进行了明确处理,该部分中的脚注指出了误解出现的位置:

      如果&E 是一个有效的指针表达式(其中& 是“地址”运算符,它生成指向其操作数的指针),则表达式(&E)->MOSE.MOS 相同。

      换句话说,&E 必须是有效的,这样等价才能成立。它存在的一个地方是:

      #include <stdio.h>
      
      struct xyzzy { int plugh; } twisty;
      struct xyzzy getTwistyCopy(void) { return twisty; }
      
      int main(void) {
          twisty.plugh = 42;
          printf("%d\n", (   getTwistyCopy()  ).plugh);
          printf("%d\n", ( &(getTwistyCopy()) )->plugh);
      }
      

      第一行printf 没问题,但第二行不行。这实际上是因为您无法获取函数返回值的地址。但是您仍然可以看到,对于任意 aa.b(&amp;a)-&gt;b 并不总是相同的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-10
        • 2019-10-27
        • 2020-07-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多