为什么不强制使用 __restrict__ 修饰符?

Why is the __restrict__ modifier not enforced?

如果函数参数被注释 const int &x 并且我尝试在函数体中执行 x++,我会收到修改只读引用的编译时错误。但是如果我像这样使用 __restrict__ 修饰符:

void foo(int & __restrict__ a, int & __restrict__ b) {
    if (a == 1)
        b = 2;
    if (a == 2)
        b = 3;
}

int main() {
    int x = 1;
    foo(x, x); // should be illegal?
    cout << x;
}

...我没有收到编译时错误。如果我 运行 未优化此代码,则输出为 3,但如果我 运行 使用 -O1 或更高,则输出为 2。检测 x 被传递两次似乎很简单,也很容易被禁止。为什么 C++ 可以防止 const 的错误使用,但不能防止 __restrict__ 的错误使用?

在非常普遍的情况下,不可能在编译时对其进行诊断。正如一个微不足道的反例,请考虑:

 void foo(int* __restrict__ a, int * __restrict__ b);

 int x;
 int y;
 std::cin >> x >> y;
 int* a = (x%2) ? &x : &y;
 int* b = (y%2) ? &x : &y;
 foo(a,b);

编译器无法知道 ab 是否指向同一个 int。实际上,如果编译器可以进行这样的分析,就不需要 __restrict__ 限定符,因为这样编译器就可以自行判断两个指针是否用于访问同一内存。

一般而言,检测 restrict 违规并不容易。假设你有一个函数

void bar(int* p1, int* p2) {
    foo(*p1, *p2);
}

编译器在这种情况下应该做什么?

在某些情况下(如在您的示例中),restrict 违规可以被某些编译器检测到。例如,带有 -Wrestrict 的 GCC 会产生警告:

warning: passing argument 1 to restrict-qualified parameter aliases with argument 2

GCC documentation-Wrestrict 上读取:

Warn when an object referenced by a restrict-qualified parameter (or, in C++, a __restrict-qualified parameter) is aliased by another argument, or when copies between such objects overlap.

您可以使用 -Werror=restrict 选项将此警告转换为错误。

您正在向后看 __restrict__

__restrict__ 是一个实现扩展,程序员可以使用它来发出 意图 信号,以最大限度地提高生成的代码质量和性能 ("optimisations")。

这不是检查,也不是对程序的附加约束。

它不是类型系统的一部分,所以它不是函数类型的一部分,所以它不能在调用点强制执行(通常)。

它就像其他一些扩展(例如 __builtin_unreachable), 用来告诉编译器一些事情。

在这种情况下,你告诉它 "I am not referring to the pointee via any other pointer"。

你不是在问 "please stop me from referring to the pointee via any other pointer"。

C 和 C++ 编译器已经在可以执行的地方执行了强大的 "aliasing" 检查。 __restrict__ 关键字是 you 告诉 it "I am sure about this" 的一种方式,以防自动别名检测无法工作(例如,由于翻译单元边界)。由于自动别名检测不起作用,因此无法强制执行 __restrict__

而且,即使可以,那也与修饰符的目的相反。