(所有引用参考N1256,即C99加技术勘误(TC3)。)
restrict 的正式定义在 §6.7.3.1 中给出。我引用下面最重要的子条款。 P 是一个restrict 限定指针,指向类型T,其范围是一个块B。如果指针表达式E 依赖于P 本身的值,而不是P 指向的值,则称它基于 P。
在每次执行B 期间,让L 为基于P 的具有&L 的任何左值。如果L 用于访问它指定的对象X 的值,则@987654336 @ 也被修改(以任何方式),则适用以下要求:
-
T 不应是 const 限定的。
- 用于访问
X 值的每个其他左值也应具有基于P 的地址。
- 就本子条款而言,修改
X 的每个访问都应视为修改P。
- 如果
P 分配了一个指针表达式E 的值,该表达式基于另一个受限指针对象P2,与块B2 关联,则B2 的执行应在执行之前开始B 的执行,或B2 的执行应在分配之前结束。
如果不满足这些要求,则行为未定义。
让我们看看规则对访问bar 中的array 的部分foo 有什么规定。我们从array 开始,这是一个在bar 的参数列表中声明的限制限定指针。为了清楚起见,我将对foo的参数进行alpha转换:
void foo(float* b, float c, unsigned int n) { /*modify b[i]*/ }
array指向的存储也是通过b修改的。第二个要点没关系,因为&array[i*n] 等同于array+(i*n)(请参阅第 6.5.3.2 节)。
如果 b 是受限制的,那么我们必须检查第四个要点:P←b、B←foo、@987654365 @←array,B2←bar。由于B 嵌套在B2 内(函数的行为就像在这里内联,请参阅§6.7.3.1.11),满足第一个条件。第三个要点也有一个实例(foo 中对b[i] 的访问),这不是问题。
但是b 没有限制资格。根据 §6.3.2.3.2,“对于任何限定符 q,指向非q 限定类型的指针可以转换为指向 q - 类型的限定版本;存储在原始指针和转换指针中的值应比较相等”。因此从array+(i*n) 到b 的转换是明确的并且具有明显的含义,因此程序的行为是定义的。此外,由于b 不是restrict 合格的,它不需要遵守任何线性条件。例如,以下foo 与bar 组合是合法的:
void qux(float *v, float *w) {
v[0] += w[0];
}
void foo(float* b, float c, unsigned int n)
{
qux(b,b);
}
添加:为了解决您“在 bar() 中将数组的一部分地址传递给 foo()”的具体问题,这不是问题:restrict 适用于指针,而不是数组,您可以对其进行算术运算(要点 2)。