如果 C 编译器知道指针没有别名,它可以执行许多优化。例如,如果我编译以下函数gcc -O2
:
int f_noalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
res += *p;
return res;
}
编译器知道读取*p
将始终评估为,x
因此生成的代码等效于为以下函数生成的代码:
int f_noalias2(int *arr, int x)
{
int *p = &arr[17];
*p = x;
return 2*x;
}
但是,如果编译器认为指针可能有别名,则不再执行此优化。例如,如果我们修改f
以便在读取 to 之间调用未知函数*p
,则生成的代码将取消引用p
两次。编译器假定该read_arr
函数可能已经修改了p
指向的值。
int f_withalias(int *arr, int x)
{
int res = 0;
int *p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
在我的特定程序中,当f
函数运行时p
,它持有的指针是唯一写入该arr
数组元素的指针。在这段时间内,代码中的其他函数可能会读取arr
,但不会写入。(他们可能会在完成运行arr
后写入其他值。)f
所以现在我有三个问题:
第一:有没有办法我可以声明我的变量来给 C 编译器这个提示?我尝试添加一个限制注释,p
但生成的代码gcc -O2
与生成的代码相同f_withalias
int f_restrict(int *arr, int x)
{
int res = 0;
int * restrict p = &arr[17];
*p = x;
res += *p;
read_array(arr);
res += *p;
return res;
}
第二:我在这里使用限制的尝试有效吗?我的理解是,restrict 意味着没有其他指针可以为 p 别名,无论是读取还是写入。但在我的情况下,该read_arr
函数显然也可以访问指向的arr
数组。p
第三:如果上一个问题的答案是“否”,我可以尝试一些不同的东西来代替restrict
吗?
基本上,我需要确保如果我这样做*p = x
,f
那么从arr[17]
. 但是,我希望 GCC 可以随意优化 tox = *p; y = *p
之类的东西x = *p; y = x
,即使两次读取之间存在函数调用。