首先是一些参考资料。C99 标准在第restrict
6.7.3 节中对此进行了说明:
通过限制限定指针访问的对象与该指针具有特殊关联。这种关联,在下面的 6.7.3.1 中定义,要求对该对象的所有访问都直接或间接地使用该特定指针的值。117)
restrict
限定符(如存储类)的预期用途register
是促进优化,并且从构成符合程序的所有预处理翻译单元中删除限定符的所有实例不会改变其含义(即,可观察的行为)。
然后(§6.7.3.1“正式定义restrict
”):
让
D
是一个普通标识符的声明,它提供了一种将对象指定P
为指向 type 的限制限定指针的方法T
。如果
D
出现在块内并且没有存储类extern
,B
则表示该块。如果D
出现在函数定义的参数声明列表中,letB
表示关联的块。否则,让B
表示 main 块(或在独立环境中程序启动时调用的任何函数块)。在下文中,指针表达式
E
被称为是基于对象的P
,如果(在执行 的某个序列点,在计算B
之前E
)修改P
为指向它以前指向的数组对象的副本将改变 的值E
. 119)请注意,“基于”仅针对具有指针类型的表达式定义。在 的每次执行期间
B
,让成为基于 的L
任何左值。如果用于访问它指定的对象的值,并且也被修改(通过任何方式),则适用以下要求:不应该是 const 限定的。用于访问 的值的每个其他左值也应具有基于 的地址。就本条而言,修改的每个访问也应被视为修改。如果分配了一个指针表达式的值,该指针表达式基于另一个与块关联的受限指针对象,则要么执行&L
P
L
X
X
T
X
P
X
P
P
E
P2
B2
B2
应在 的执行之前开始B
,或 的执行B2
应在转让之前结束。如果不满足这些要求,则行为未定义。
正如一些人指出的那样,这说明了规则(标准中的示例 4):
{
int * restrict p1;
int * restrict q1;
p1 = q1; // undefined behavior
{
int * restrict p2 = p1; // valid
int * restrict q2 = q1; // valid
p1 = q2; // undefined behavior
p2 = q2; // undefined behavior
}
}
现在,我的第一个问题是:为什么可以从外部受限指针分配给内部受限指针?
我的理解是没有什么可以禁止的,它有明显的别名:
int * restricted x = /* ... */ ;
{
int * restricted y = x;
*x = 3;
printf("%d\n", *y); // 3
*y = 4;
printf("%d\n", *x); // 4
}
当然,别名集仅限于两个指针。
因此我的第二个问题是:从外部分配到内部(允许),而不是从内部分配到外部(禁止,例如p1 = q1;
在上面的第一个示例中)有什么区别?