首先参考一些。 C99 Standard在第6.7.3节中说明了restrict
:
通过限制限定指针访问的对象具有 与该指针的特殊关联。这种关联,定义于 下面的6.7.3.1要求对该对象的所有访问直接或间接使用该特定指针的值。 117)意图 使用
restrict
限定符(如register
存储类)是 促进优化,并从中删除限定符的所有实例 所有预处理翻译单元组成一个合规的程序 不改变其含义(即可观察的行为)。
然后(§6.7.3.1“restrict
的正式定义”):
让
D
成为提供方法的普通标识符的声明 将对象P
指定为类型T
的限制限定指针。如果
D
出现在某个块内且没有存储类extern
, 让B
表示该块。如果D
出现在参数列表中 函数定义的声明,让B
表示关联的 块。否则,让B
表示主要块(或块) 在独立的程序启动时调用的任何函数 环境)。在下文中,指针表达式
E
在对象P
上被称为基于的 (在B
执行之前的某个序列点 评估E
)修改P
以指向数组对象的副本 它以前指出的将改变E
的值。 119)注意 ''based''仅针对具有指针类型的表达式定义。在每次执行
B
期间,让L
为基于&L
P
的任何左值L
。如果X
用于访问对象X
的值 指定,T
也被修改(以任何方式),然后是以下内容 要求适用:X
不得为const限定。每个其他左值 用于访问P
的值的地址也应基于X
。 修改P
的每个访问权限也应被视为修改P
本条款的目的。如果为E
分配了a的值 指针表达式P2
,它基于另一个受限制的指针 对象B2
,与块B2
关联,然后执行B
应在执行B2
之前开始,或执行{ 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 } }
在转让之前结束。如果不满足这些要求,那么 行为未定义。
作为some have pointed out,这说明了规则(标准中的示例4):
int * restricted x = /* ... */ ;
{
int * restricted y = x;
*x = 3;
printf("%d\n", *y); // 3
*y = 4;
printf("%d\n", *x); // 4
}
现在,我的第一个问题是这样的:为什么可以从外部限制指针分配到内部指针?
我的理解是没有任何禁止这个,它有明显的别名:
p1 = q1;
当然,这组别名仅限于两个指针。
因此我的第二个问题:从外部到内部(允许)分配的区别是什么,但不是从内部到外部(禁止,例如上面第一个示例中的{{1}})?
答案 0 :(得分:1)
我认为这些规则旨在满足两个目标:
允许创建一个类似于将参数传递给函数调用时自然创建的临时指针,而不要求使用指针的代码移动到物理上独立的函数中。
确保显示指针派生的图形没有周期(意味着如果指针x是从y派生的,或者是直接或间接派生自y的任何内容,则y不能从x派生,也不能直接派生或间接衍生自x)。虽然规则可能比实现#2绝对必要的规则更严格,但几乎所有满足第二个要求的有用情况也满足所写的规则,并且编译器很难从restrict
中获得很多好处。没有的案例。
restrict
限定词远非完美,但它仍然比大多数替代品更好。
答案 1 :(得分:-4)
这些都不是未定义的行为。你可以在所有你喜欢的限制指针之间进行分配。如果以错误的方式分配限制指针指向的对象,则可能会出现未定义的行为。
在你的第二个例子中,指针y是从x派生的,所以首先分配给* x,然后分配给* y的同一个变量,也可以。
你没有阅读法律术语,你真的想过应该达到什么样的“限制”吗?