restrict 关键字

restrict 关键字

Content #

C99 标准新增了一个名为 restrict 的关键字,可以优化代码的执行。该关键字只能用于指针类型,用以表明该指针是访问对应数据的唯一方式。

在计算机领域,有一个名为 aliasing 的概念。这个概念是说内存中的某一个位置,可以通过程序中多于一个的变量来访问或修改其包含的数据。而这可能会导致一个潜在的问题:即当通过其中的某个变量修改数据时,便会导致所有与其他变量相关的数据访问发生改变。

因此,aliasing 使得编译器难以对程序进行过多的优化。而在 C 语言中, restrict 关键字便可以解决这个问题。当然,如果你学习过 Rust,这也是其所有权机制的核心内容。下面我们来看一个例子。

#include <stdio.h>
void foo(int* x, int* y, int* restrict z) {
  *x += *z;
  *y += *z;
}
int main(void) {
  int x = 10, y = 20, z = 30;
  foo(&x, &y, &z);
  printf("%d %d %d", x, y, z);
  return 0;
}

在这段代码中,函数 foo 共接收三个整型指针参数,它的功能是将第三个指针指向变量的值,累加到前两个指针指向的变量上。其中,第三个参数 z 被标记为了 restrict ,这表明我们向编译器做出了这样一个承诺:即在函数体 foo 内部,我们只会使用变量 z 来引用传入函数第三个指针参数对应的内存位置,而不会发生 aliasing。这样做使得编译器可以对函数的机器码生成做进一步优化。

来看下上面这段 C 代码对应的汇编代码:

foo:
        mov     eax, DWORD PTR [rdx]
        add     DWORD PTR [rdi], eax
        add     DWORD PTR [rsi], eax
        ret

在使用 restrict 关键字标注了 foo 函数的第三个参数后,在为指针 y 进行值累加前,编译器不会再重复性地从内存中读取指针 z 对应的值(对应上面第一行代码)。而这对程序的执行来说,无疑是一种性能上的优化。

另外你需要注意的是,若一个指针已被标记为 restrict ,但在实际使用时却发生了 aliasing,此时的行为是未定义的。

Viewpoints #

From #

18|极致优化(上):如何实现高性能的 C 程序?