有没有办法告诉C编译器指针没有别名存储?

时间:2018-09-19 06:37:22

标签: c restrict restrict-qualifier

如果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之类的东西进行优化。

1 个答案:

答案 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的断言