题
我对有关受限指针的规则有点困惑。也许有人可以帮助我。
如下定义嵌套受限指针是否合法:
int* restrict a; int* restrict b; a = malloc(sizeof(int)); // b = a; <-- assignment here is illegal, needs to happen in child block // *b = rand(); while(1) { b = a; // Is this legal? Assuming 'b' is not modified outside the while() block *b = rand(); }
按如下方式派生受限指针值是否合法:
int* restrict c; int* restrict d; c = malloc(sizeof(int*)*101); d = c; for(int i = 0; i < 100; i++) { *d = i; d++; } c = d; // c is now set to the 101 element, is this legal assuming d isn't accessed? *c = rand();
谢谢!安德鲁
解决方案
作为参考,这里是 restrict
限定符相当复杂的定义(来自 C99 6.7.3.1“restrict 的正式定义”):
让 D 成为普通的宣言 标识符,提供 将对象 P 指定为 指向类型 T 的限制限定指针。
如果 D 出现在块内,并且 没有存储类 extern,设 B 表示块。如果 D 出现在参数列表中 函数的声明 定义,设 B 表示 关联的块。否则,让 B 表示 main 的块(或块 的任何函数被调用 在独立式中启动程序 环境)。
在下文中,指针 据说表达式 E 基于 对象 P if (在某个序列点 在执行 B 之前 评估 E) 将 P 修改为点 将数组对象复制到 它以前指出的会改变 E 的值。请注意,“基于”是 仅针对具有 指针类型。
在每次执行 B 期间,设 L 任何具有基于 P 的 &L 的左值。如果 L 用于访问 它指定的对象 X,X 是 也修改了(无论如何),然后 以下要求适用:T 应 不具有常量资格。每隔一个 lvalue 用于访问 X 的值 还应根据以下条件确定其地址 P.每个修改 X 的访问都应 也考虑修改 P,为 本款的目的。如果P 被分配指针的值 基于另一个的表达式 E 受限制的指针对象 P2, 与块 B2 关联,然后 B2 的执行应在 执行 B,或 B2 的执行应在 分配。如果这些 不满足要求,则 行为未定义。
这里执行 B 意味着 部分执行 对应于 具有标量类型的对象的生存期 和自动存储持续时间 与 B 相关。
我对上述内容的阅读意味着,在你的第一个问题中, a
不能分配给 b
, ,即使在“子”块内 - 结果也是未定义的。如果可以进行这样的分配 b
是在那个“子块”中声明的,但是自从 b
声明的范围与 a
, ,无法进行分配。
对于问题 2,之间的分配 c
和 d
也会导致未定义的行为(在这两种情况下)。
标准中的相关部分(对于两个问题)是:
如果为 P 赋值 指针表达式 E,基于 另一个受限制的指针对象 P2, 与块 B2 关联,然后 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 } }
其他提示
这 restrict
类型限定符是 指示 向编译器表明,如果内存由 restrict
-限定指针被修改,没有其他指针将访问同一内存。编译器可能会选择优化涉及的代码 restrict
- 限定指针,否则可能会导致不正确的行为。 程序员有责任确保限制限定指针按其预期用途使用。否则,可能会导致未定义的行为。 (关联)
正如您从上面的描述中看到的,您的两个赋值都是非法的,这可能在某些编译器生成的可执行文件中有效,但在其他编译器中会中断。不要指望编译器本身会发出错误或警告: restrict
只是提供了执行某些优化的机会,它可以选择不执行,就像下面的情况一样 volatile
.