如果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
,以便在对*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
添加一个限制注释,但是在{{1下}}与gcc -O2
f_withalias
第二个:我在这里使用限制的尝试是否有效?我的理解是,限制意味着没有其他指针可以别名p进行读取或写入。但就我而言,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;
}
函数显然也可以访问read_arr
指向的arr
数组。
第三:如果上一个问题的答案为“否”,我可以尝试代替p
来尝试其他方式吗?
基本上,我需要确保如果我在restrict
中执行*p = x
,那么从f
读取的其他函数将立即注意到该写入。但是,即使两次读取之间存在函数调用,我也希望GCC可以将arr[17]
到x = *p; y = *p
之类的东西进行优化。
答案 0 :(得分:1)
首先:有没有一种方法可以声明我的变量以将此提示提供给C编译器?
int * restrict p = &arr[17];
断言,在块的持续时间内,仅p
和基于p
的指针表达式将用于访问任何指向对象p
的指针(对象除外)不会以任何方式修改)。这样可以优化您建议的res += *p;
。 GCC没有如此优化的事实是GCC中的质量问题。
第二:我在这里尝试使用限制有效吗? … 基本上,我需要确保如果我在f中执行* p = x,那么从arr [17]读取的其他函数将立即注意到该写操作。
后一个属性不是restrict
的有效使用。 p
被声明为restrict
并且arr[17]
是通过p
进行修改的事实意味着,不应使用非基于p
的指针来访问{{1} }在包含arr[17]
的代码块执行期间,甚至无法读取。因此,如果p
中的某些内容确实读取了read_array
(使用arr[17]
,而不是基于arr
),则将违反p
的断言