sup*_*cat 9 c optimization gcc clang
即使C标准明确认识到,指向一个对象“刚刚过去”的地址可能偶然地与指向“指向”另一个不相关对象的地址相等,但gcc和clang似乎都在假设没有指针的情况下运行如示例所示,观察到指向刚刚超过一个对象的对象可能指向另一个对象:
#include <stdio.h>
int x[1],y[1];
int test1(int *p)
{
y[0] = 1;
if (p==x+1)
*p = 2; // Note that assignment is to *p and not to x[1] !!!
return y[0];
}
int test2(int *p)
{
x[0] = 1;
if (p==y+1)
*p = 2; // Note that assignment is to *p and not to y[1] !!!
return x[0];
}
int (*volatile test1a)(int *p) = test1;
int (*volatile test2a)(int *p) = test2;
int main(void) {
int q;
printf("%llX\n",(unsigned long long)y - (unsigned long long)x);
q = test1a(y);
printf(">> %d %d\n", y[0], q);
q = test2a(x);
printf(">> %d %d\n", x[0], q);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
通过阅读标准,此程序在标记的行上的有效输出>>
将为>> 1 1
或>> 2 2
,但>> 2 1
其中一行的ideone输出上的gcc 以及从我可以知道clang生成的代码中的输出也将对另一行进行同样的处理。
我很清楚,p
比较等于的事实x[1]
并不意味着后者可以用于访问与*p
(或任何对象)相同的对象,但是我不知道标准中的任何内容禁止计算x+1
结果指针和之间的或比较p
。我还知道,没有任何东西会导致这种比较p
无法用于访问其拥有地址的对象。
是否有任何合理的阅读任何C标准的发布版本或草稿版本,在上述版本中上述代码将调用未定义行为,或者在该版本下,从test1
和test2
不需要返回的值分别与y[0]
或的最终值匹配x[0]
,或者是优化程序?用clang和gcc设计来处理不是标准的已发布或草稿版本的方言?
PS-根据标准草案N1570 6.5.9p6:
6当且仅当两个都是空指针时,两个指针比较相等,两个都是指向同一对象的指针(包括指向对象和它的开始处的子对象的指针)或函数,并且都是指向同一对象的最后一个元素的指针数组对象,或者一个是指向一个数组对象末尾的指针,另一个是指向另一个数组对象的起点的指针,而该数组对象恰好紧随地址空间中的第一个数组对象。
该标准不以任何方式暗示x[]
必须遵循y[]
,反之亦然,但似乎明确规定了将指向过去的指针x
与之进行比较y
并视为相等的可能性。
这确实是一个编译器错误。在大多数情况下,当某些指针、数组和整数的p == x+i
计算结果为 true时,确实必然指向( 中的元素,或者程序正在执行具有未定义行为的代码,在这种情况下,允许编译器假设指向中的元素)。如果确实指向 中的元素,则该元素确实无法更改,因此编译器生成返回最近分配给 1 的代码是正确的。线索表明编译器已尝试进行优化,其中 \xe2\x80\x9clearns\xe2\x80\x9d 关于p
x
i
p
x
p
x
p
x
*p = 2;
y[0]
y[0]
p
通过比较的真实性。
x+i
当指向超出数组末尾的 1时,此推导失败x
。在 C 2018 6.5.9 6 中,标准告诉我们,即使p
指向与无关的不同对象x
(但恰好在内存中紧随其后),此比较也可能评估为 true。编译器\xe2\x80\x99s的推导应该更加有限。给定p+j == x+i
,其中x
是一个元素数组n
,计算为 true 的事实仅意味着指向for \xe2\x88\x92 \xe2\x89\xa4 < + \xe2\x88\x92p+k
的元素。(在问题的情况下,=1、=0 和=0,失败 0\xe2\x88\x921 \xe2\x89\xa4 0 < 1+0\xe2\x88\x921。)x
j
i
k
n
j
i
i
j
k
(请注意,上面提出的标准意味着,对于问题中的情况,p-1
指向 的一个元素x
,因为 0\xe2\x88\x921 \xe2\x89\xa4 \xe2\x88\x921 < 0 成立,但我们知道p
指向y
且对于指向 无效x
。但是使用它来访问p[-1]
具有标准未定义的行为,这意味着任何假设都是允许的,包括这p[-1]
是x
。因此允许编译器使用该标准。)