作为参考,这里是restrict
限定符相当复杂的定义(来自 C99 6.7.3.1“限制的正式定义”):
令 D 是一个普通标识符的声明,它提供了一种将对象 P 指定为指向类型 T 的限制限定指针的方法。
如果 D 出现在一个块内并且没有存储类 extern,则让 B 表示该块。如果 D 出现在函数定义的参数声明列表中,则让 B 表示关联的块。否则,让 B 表示 main 块(或在独立环境中程序启动时调用的任何函数块)。
在下文中,如果(在对 E 求值之前执行 B 的某个序列点)修改 P 以指向它以前指向的数组对象的副本,则称指针表达式 E 基于对象 P会改变 E 的值。请注意,“基于”仅针对具有指针类型的表达式定义。
在每次执行 B 期间,令 L 为基于 P 具有 &L 的任何左值。如果 L 用于访问它指定的对象 X 的值,并且 X 也被修改(通过任何方式),则适用以下要求: T 不应是 const 限定的。用于访问 X 值的每个其他左值也应具有基于 P 的地址。就本子条款而言,修改 X 的每个访问也应视为修改 P。如果为 P 分配了一个指针表达式 E 的值,该指针表达式 E 基于与块 B2 关联的另一个受限指针对象 P2,则 B2 的执行应在 B 的执行之前开始,或者 B2 的执行应在任务。如果不满足这些要求,则行为未定义。
这里 B 的执行是指程序执行的一部分,对应于标量类型和与 B 关联的自动存储持续时间的对象的生命周期。
我对上述内容的阅读意味着在您的第一个问题中,即使在“子”块内,a
也不能分配给b
- 结果未定义。b
如果在该“子块”中声明,则可以进行这样的分配,但由于b
在与 相同的范围内声明,a
因此无法进行分配。
c
对于问题 2,和之间的分配d
也会导致未定义的行为(在这两种情况下)。
标准中的相关位(对于两个问题)是:
如果为 P 分配了一个指针表达式 E 的值,该指针表达式 E 基于与块 B2 关联的另一个受限指针对象 P2,则 B2 的执行应在 B 的执行之前开始,或者 B2 的执行应在任务。
由于受限指针与同一个块相关联,因此块 B2 不可能在 B 执行之前开始,或者 B2 在分配之前结束(因为 B 和 B2 是同一个块)。
该标准给出了一个非常清楚的示例(我认为 -restrict
定义的 4 个短段落的清晰度与 C++ 的名称解析规则相当):
示例 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
}
}