C 指针别名是如何工作的?
问题7: 第二个结果如何可能?我不太明白这个解释是如何通过引用严格的别名来解释结果的。编译器是否完全忽略了第(2)行 引用: <>在C或C++中,严格的混叠规则规定,<强>指针 如果函数中的参数指向 基本不同的类型,除了char*和void*,它们可能 任何其他类型的别名。某些编译器允许严格的别名规则 关闭,以便任何指针参数都可以别名任何其他参数 指针参数。在这种情况下,编译器必须假设 可以通过这些指针访问别名。这可以防止一些 正在进行的优化 这就是违反规则的地方:C 指针别名是如何工作的?,c,pointers,language-lawyer,strict-aliasing,type-punning,C,Pointers,Language Lawyer,Strict Aliasing,Type Punning,问题7: 第二个结果如何可能?我不太明白这个解释是如何通过引用严格的别名来解释结果的。编译器是否完全忽略了第(2)行 引用: 在C或C++中,严格的混叠规则规定,指针 如果函数中的参数指向 基本不同的类型,除了char*和void*,它们可能 任何其他类型的别名。某些编译器允许严格的别名规则 关闭,以便任何指针参数都可以别名任何其他参数 指针参数。在这种情况下,编译器必须假设 可以通过这些指针访问别名。这可以防止一些 正在进行的优化 这就是违反规则的地方: f((int *) &a, &
f((int *) &a, &a);
^ aliasing to different type (a is 'long')
^ passing the same variable with different type
问题在于,假设有严格的别名规则,函数的第一个和第二个参数指向另一个位置,因为它们的类型不同。这就是作者解释的原因:
因此,我们可以假设任何long都没有改变
在这里:printf(“2.v=%ld\n”,*l)代码>一个long
值被取消引用
这就是为什么这部分(2)在两个编译器上都是未定义的行为。编译器不会忽略或省略第(2)部分,它会被执行,调用方作用域中a
的值会以某种依赖于系统的方式被修改,但编译器可以假设函数f()
,通过指针i
修改int
不会修改l
指向的long
,因此它可以将第一个printf()
读取的值重新用作第二个printf
的参数
第二个编译器似乎会生成这样做的代码,而第一个编译器生成的代码会重新读取l
所指向的值。实际上,编译器选项(如优化设置)可以更改此行为,这与将此代码描述为具有未定义行为的C标准一致。第二个结果是由于*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) */
}
这是未定义的行为。Upd:顺便说一句,看了这篇文章,它是关于未定义行为的。你读过吗?我猜你的编译器2(不管它是什么)可能正在做一些过早优化
@Zakir编译器不会受到过早优化的影响…@Zakir你说的“过早优化”是什么意思?使用同一编译器的不同编译器或编译器选项具有不同的行为这一事实并不是描述代码具有未定义行为的理由。
f((int *) &a, &a);
^ aliasing to different type (a is 'long')
^ passing the same variable with different type
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) */
}