这个指针别名如何工作?

Zos*_*oso 2 c pointers strict-aliasing language-lawyer type-punning

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;
}
Run Code Online (Sandbox Code Playgroud)

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

1. v=10    2. v=11    3. v=11
1. v=10    2. v=10    3. v=11
Run Code Online (Sandbox Code Playgroud)

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

syn*_*gma 6

引用维基百科:

在C或C++中,由严格别名规则强制要求,如果函数中的指针参数指向 基本上不同的类型,则假定它们不是别名,除了char*和void*,它们可能是任何其他类型的别名.某些编译器允许关闭严格别名规则,因此任何指针参数都可以为任何其他指针参数设置别名.在这种情况下,编译器必须假定通过这些指针的任何访问都可以是别名.这可以防止进行一些优化.

这是违反规则的地方:

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

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

因此,我们可以假设任何长期都没有改变.

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

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