【问题标题】:How does this pointer aliasing work?这个指针别名是如何工作的?
【发布时间】:2017-06-01 18:16:21
【问题描述】:

https://kukuruku.co/post/i-do-not-know-c/

问题 #7:

#include <stdio.h>
void f(int *i, long *l)
{
  printf("1. v=%ld\n", *l); /* (1) */
  *i = 11;                  /* (2) */
  printf("2. v=%ld\n", *l); /* (3) */
}
int main()
{
  long a = 10;
  f((int *) &a, &a);
  printf("3. v=%ld\n", a);
  return 0;
}

小端系统上两个不同编译器的输出是:

1. v=10    2. v=11    3. v=11
1. v=10    2. v=10    3. v=11

第二个结果怎么可能?我不太明白通过引用严格别名来解释结果的解释。编译器是否完全忽略第 (2) 行?

【问题讨论】:

  • 这是未定义的行为。 更新:顺便说一句,看了这篇文章,它关于未定义的行为。你读过吗?
  • 我猜你的编译器 2(不管它可能是什么)可能正在做一些premature optimization
  • @Zakir 编译器不易受到过早优化....
  • @Zakir “过早优化”是什么意思?

标签: c pointers language-lawyer strict-aliasing type-punning


【解决方案1】:

引用Wikipedia:

在 C 或 C++ 中,按照严格的别名规则的要求,指针 如果函数中的参数指向,则假定它们不是别名 完全不同的类型,除了 char* 和 void*,它们可能 任何其他类型的别名。一些编译器允许严格的别名规则 被关闭,以便任何指针参数可以别名任何其他 指针参数。在这种情况下,编译器必须假定任何 通过这些指针访问可以别名。这可以防止一些 正在进行优化。

这是违反规则的地方:

f((int *) &a, &a);
    ^ aliasing to different type (a is 'long')
              ^ passing the same variable with different type

问题是假设严格的别名规则,函数的第一个和第二个参数指向另一个位置,因为它们是不同的类型。这就是作者解释的原因:

因此,我们可以假设任何多头都没有改变

在这里:printf("2. v=%ld\n", *l); long 值被取消引用。

这就是为什么这部分 (2) 在两个编译器上都是未定义的行为。

【讨论】:

    【解决方案2】:

    编译器不会忽略或省略第 (2) 部分,它会被执行并且调用者范围内的 a 的值会以某种与系统相关的方式进行修改,但编译器可以假设内部函数 f(),通过指针i修改int不会修改l指向的long,因此它可以重用为第一个printf()读取的值作为第二个printf的参数。

    第二个编译器似乎生成了执行此操作的代码,而第一个编译器生成的代码重新读取了l 指向的值。事实上,优化设置等编译器选项可以改变这种行为,这与将这段代码描述为具有未定义行为的 C 标准是一致的。

    【讨论】:

    • 不同编译器或具有相同编译器的编译器选项具有不同行为这一事实不是描述代码具有未定义行为的理由。
    【解决方案3】:

    第二个结果是由于*l 的值不能在(1) 和(3) 之间变化。 (严格的别名规则确保了这一点。)

    这样,程序只需要计算一次它的值,编译器就生成了等价于

    void f(int *i, long *l)
    {
      long l2 = *l;
      printf("1. v=%ld\n", l2); /* (1) */
      *i = 11;                  /* (2) */
      printf("2. v=%ld\n", l2); /* (3) */
    }
    

    【讨论】:

      猜你喜欢
      • 2018-10-21
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 2023-01-10
      • 2021-04-21
      • 2020-09-19
      • 2011-05-30
      • 2012-10-08
      相关资源
      最近更新 更多