为什么没有强制执行__restrict__修饰符



如果函数参数被注释为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__的不良使用?

您正在向后看__restrict__

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

它不是检查,也不是对程序添加的约束。

它不是类型系统的一部分,因此也不是函数类型的一部分。因此(通常(不能在调用站点强制执行它。

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

在这种情况下,您告诉它"我不是通过任何其他指针来指代指针对象"。

你并不是在问它"请阻止我通过任何其他指针引用指针对象"。

C和C++编译器已经在可能的地方执行了强大的"混叠"检查。__restrict__关键字是在自动混叠检测无法工作(例如,由于翻译单元边界(的情况下告诉"我对此很确定"的一种方式。由于自动混叠检测无法工作,因此无法强制执行__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会产生警告:

警告:传递参数1以限制具有参数2 的合格参数别名

-Wrestrict上的GCC文档读取:

restrict限定参数(或者在C++中,__restrict限定参数(引用的对象被另一个参数别名时,或者当这些对象之间的副本重叠时,发出警告。

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

最新更新