[如果给函数参数加注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);
[编译器无法知道a
和b
是否指向相同的int
。实际上,如果编译器可以进行这种分析,则不需要__restrict__
限定符,因为这样编译器可以自己确定是否使用了两个指针来访问同一内存。
通常很难检测到restrict
违规。假设您有一个功能
void bar(int* p1, int* p2) {
foo(*p1, *p2);
}
在这种情况下,编译器应该做什么?
[在某些情况下,例如您的示例,可以检测到restrict
违例,并且某些编译器可以检测到。例如,带有-Wrestrict
的GCC会产生警告:
警告:将参数1传递给带有参数2的限定条件的参数别名
documentation上的GCC -Wrestrict
读取:
警告:当
restrict
限定的参数(或C ++中,__restrict
限定的参数)引用的对象被另一个参数别名时,或当此类对象之间的副本重叠时。
您可以使用-Werror=restrict
选项将此警告变成错误。
您正在向后看__restrict__
。
__restrict__
是实现扩展,程序员可以用来发信号通知intent。
不是检查,也不是程序的约束。
它不是类型系统的一部分,因此它也不是函数类型的一部分,因此不能在调用站点上强制执行(通常)。
类似于其他扩展名(例如__builtin_unreachable
),you用来告诉编译器一些东西。
在这种情况下,您是在告诉我“我不是通过任何其他指针来指望指针”。
您并不是在问它“请阻止我通过任何其他指针来指望该指向对象”。
C和C ++编译器已经在可能的地方执行了严格的“混叠”检查。 __restrict__
关键字是you告诉it“我确定这一点”的一种方法,在自动混叠检测无法工作的情况下(例如由于翻译单元边界)。由于自动别名检测无法正常工作,因此无法强制执行__restrict__
。
而且,即使可能,也与修饰符的目的相反。