如果我们有一个函数:
void func(int *restrict a, int *restrict b, int *restrict c) {
*c = *a + *b;
}
原则上,这段代码可能会导致一些错误:
int aa = 1;
func(&aa, &aa, &aa);
因为 in func
,*a
*b
*c
将是同一个对象。但是为什么这段代码可以编译成功呢?
如果我们有一个函数:
void func(int *restrict a, int *restrict b, int *restrict c) {
*c = *a + *b;
}
原则上,这段代码可能会导致一些错误:
int aa = 1;
func(&aa, &aa, &aa);
因为 in func
,*a
*b
*c
将是同一个对象。但是为什么这段代码可以编译成功呢?
restrict
基本上是程序员对编译器的承诺,即指针是唯一用于访问它指向的对象(在指针范围内)的指针。
编译器(通常)不会检查该承诺 - 它将责任留给程序员。如果程序员弄错了,未定义的行为将是惩罚。
通常无法检测到这种类型的 UB。调用函数可能已经从另一个编译单元接收到指针。这就是为什么这通常是“只是”UB,因为作为一个约束,它在编译时无法检测到。
不过,没有什么能阻止编译器在这种情况下发出诊断。为什么您的编译器实施者认为实施这样的诊断不值得,您必须直接在那里询问。
的全部意义restrict
在于告诉编译器它可以假设受限指针指向的内存与该点可访问的任何其他内存之间没有重叠,因此编译器可以在没有这种假设的情况下进行不可能的优化。如果编译器可以自己判断没有这种重叠,那么就不需要关键字。使代码func
成为错误会破坏关键字的整个目的。至于 的调用func
: 由于编译器通常无法判断是否违反了限制,因此不需要注意它可以判断的实例。一些具有适当警告级别的高质量编译器可能会func
在您的问题中调用等情况下发出警告。
这段代码可以编译成功,因为它没有任何问题。
简单地说,它是一个符合标准的代码。该标准仅要求对格式错误的代码进行诊断,而此代码不是。
这就像,你可以向自己的头部开枪,并不意味着你应该这样做,如果你只这样做,你就不能怪别人没有阻止你这样做。