根据第C99 Draft N1256条第6.7.3条:
通过限制限定指针访问的对象具有特殊的关联
用那个指针.此关联在下面的6.7.3.1中定义,要求所有访问
该对象直接或间接地使用该特定指针的值
使用RESTRICE限定符(如寄存器存储类)是为了提升
优化,并从所有预处理转换中删除限定符的所有实例
构成一致性程序的单元不改变其含义(即,可观察
行为).
将指针声明为restrict可确保编译器不会有其他指针修改受限指针所指向的内存位置.
但是,您仍然可以有两个指向同一内存区域的受限指针.
同样,C99 Draft N1256个中的6.7.3.1中的示例3也派上了用场:
void h(int n, int * restrict p, int * restrict q, int * restrict r)
{
int i;
for (i = 0; i < n; i++)
p[i] = q[i] + r[i];
}
以下是该标准的 comments :
[h的函数参数声明]说明了如何通过两个受限指针为未修改的对象设置别名.具体地说,如果a和b是不相交的数组,则h(100,a,b,b)形式的调用定义了行为,因为数组b在函数h内不被修改.
所以,你的问题的答案是:不,这不是GCC或Clang错过的优化.
正如Peter在 comments 中指出的那样,可能缺少基于以下与受限指针相关的未定义行为的优化:
通过限制限定指针访问已修改的对象
常量限定类型,或通过限制限定指针和另一个
两者不是基于同一对象(6.7.3.1).
从本质上讲,如果没有使用两个受限指针来修改它们所指向的数据(这是您的函数foo和我的答案中的函数h的情况),即使它们指向相同的内存区域,也不会发生未定义的行为.因此,编译器不能在编译时说明它们的值:它们可以是相同的,也可以不同.
然而,一种不同的情况如下:
int compare_pointers(int *restrict ptr1, int *restrict ptr2)
{
*ptr1 = 0;
*ptr2 = 1;
if (ptr1 != ptr2) {
return 1234;
} else {
return 4321;
}
}
由于这两个指针都用于修改数据,因此它们必须与不同的内存区域相关联,否则将出现未定义的行为(这是关键字restrict
的结果),因此优化可能会删除后续比较并返回1234.然而,GCC和克兰都没有像彼得的 comments 所显示的那样进行这样的优化.