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

Is there a way to tell the C compiler that a pointer has no aliasing stores?

如果 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 读取,但不会写入。 (他们可能会在 f 完成 运行 之后将其他值写入 arr。)

所以现在我有三个问题:

首先:有没有一种方法可以声明我的变量以向 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 的尝试有效吗?我的理解是 restrict 意味着没有其他指针可以为 p 作为读或写的别名。但在我的例子中,read_arr 函数显然也可以访问 p 指向的 arr 数组。

第三:如果上一个问题的答案是"no",有什么不同的东西可以代替restrict吗?

基本上,我需要确保如果我在 f 中执行 *p = x,那么从 arr[17] 读取的其他函数会立即注意到该写入。但是,我希望 GCC 可以自由地将 x = *p; y = *p 优化为 x = *p; y = x,即使两次读取之间存在函数调用。

First: Is there a way I can declare my variables to give this hint to the C compiler?

int * restrict p = &arr[17]; 断言只有 p 和基于 p 的指针表达式将用于访问任何对象 p 在块的持续时间内指向(除了对于未以任何方式修改的对象)。这可以实现您建议的 res += *p; 的优化。 GCC没有这么优化是GCC的质量问题。

Second: Is my attempt to use restrict here valid? … Basically, I need to make sure that if I do *p = x in f then that write will be immediately noticed by other functions reading from arr[17].

后者 属性 不是 restrict 的有效用法。 p 声明为 restrict 并且 arr[17] 通过 p 修改的事实意味着不应该使用不基于 p 的指针来访问 arr[17] 在包含 p 的块执行期间,甚至不用于读取。因此,如果 read_array 中的某些内容确实读取了 arr[17](使用 arr,它不是基于 p),这将违反 restrict 断言.