16

首先是一些参考资料。C99 标准在第restrict6.7.3 节中对此进行了说明:

通过限制限定指针访问的对象与该指针具有特殊关联。这种关联,在下面的 6.7.3.1 中定义,要求对该对象的所有访问都直接或间接地使用该特定指针的值。117)restrict限定符(如存储类)的预期用途register是促进优化,并且从构成符合程序的所有预处理翻译单元中删除限定符的所有实例不会改变其含义(即,可观察的行为)。

然后(§6.7.3.1“正式定义restrict”):

D是一个普通标识符的声明,它提供了一种将对象指定P为指向 type 的限制限定指针的方法T

如果D出现在块内并且没有存储类externB则表示该块。如果D出现在函数定义的参数声明列表中,letB表示关联的块。否则,让B表示 main 块(或在独立环境中程序启动时调用的任何函数块)。

在下文中,指针表达式E被称为是基于对象的P,如果(在执行 的某个序列点,在计算B之前E)修改P为指向它以前指向的数组对象的副本将改变 的值E. 119)请注意,“基于”仅针对具有指针类型的表达式定义。

在 的每次执行期间B,让成为基于 的 L任何左值。如果用于访问它指定的对象的值,并且也被修改(通过任何方式),则适用以下要求:不应该是 const 限定的。用于访问 的值的每个其他左值也应具有基于 的地址。就本条而言,修改的每个访问也应被视为修改。如果分配了一个指针表达式的值,该指针表达式基于另一个与块关联的受限指针对象,则要么执行&LPLXXTXPXPPEP2B2B2 应在 的执行之前开始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;在上面的第一个示例中)有什么区别?

4

2 回答 2

2

我认为这些规则旨在满足两个目标:

  1. 允许创建类似于将参数传递给函数调用时自然创建的临时指针,而无需将使用指针的代码移动到物理上独立的函数中。

  2. 确保显示指针派生的图形没有循环(意味着如果指针 x 派生自 y 或任何直接或间接从 y 派生的东西,则 y 不能派生自 x 或任何直接或间接派生自 x 的东西) . 虽然规则可能比实现#2 的绝对必要条件更严格,但几乎所有满足第二个要求的有用案例也都满足所编写的规则,并且编译器很难从不满足第二个要求restrict的案例中获得很多好处。吨。

不幸的是,规则的作者似乎并没有做出任何特别的努力来考虑所有可能的极端情况并确保标准中的规则可以合理地应用于所有这些情况。有两种使用情况,其中的语义restrict清晰且合理:

  1. 函数接收restrict-qualified 指针,在这种情况下,限定符应该影响传递给 function 的指针值,与可能存储在参数中的任何其他内容无关。

  2. 具有限制限定符的自动对象的定义包括一个初始化表达式,在这种情况下,限定符应该影响用于初始化的指针值,而与对象中可能存储的任何其他内容无关。

限制“保护”除通过上述两种方法之一存储到指针中的地址以外的任何内容的语义充其量是相当模糊的,即使尝试添加标准中的范围规则也是如此。在其他情况下添加限制限定符更有可能破坏某些东西以产生有用的效果,即使最有可能的结果是限定符没有任何效果。

于 2017-05-17T20:46:11.737 回答
-3

这些都不是未定义的行为。您可以根据自己的喜好在限制指针之间进行分配。如果您以错误的方式分配给限制指针指向的对象,则可能会发生未定义的行为。

在您的第二个示例中,指针 y 是从 x 派生的,因此首先分配给 *x,然后分配给与 *y 相同的变量也可以。

与其阅读法律术语,您是否真的想过“限制”应该达到什么目的?

于 2015-03-26T11:00:17.593 回答