5

我对限制指针的规则有点困惑。也许有人可以帮助我。

  1. 如下定义嵌套的受限指针是否合法:

    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();
    }
    
  2. 如下推导受限指针值是否合法:

    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();
    

谢谢!安德鲁

4

2 回答 2

4

作为参考,这里是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
    }
}
于 2010-09-27T04:05:08.497 回答
1

restrict类型限定符向编译器表明,如果修改了 -qualified 指针寻址的内存,则没有restrict其他指针将访问同一内存。编译器可能会选择以restrict可能导致不正确行为的方式优化涉及 -qualified 指针的代码。程序员有责任确保按预期使用限制限定的指针。否则,可能会导致未定义的行为。链接

正如您从上面的描述中看到的那样,您的两个分配都是非法的,它们可能在某些编译器生成的可执行文件中工作,但在其他编译器中中断。不要期望编译器本身会发出错误或警告,因为restrict它只是提供了执行某些优化的机会,它可以选择不执行,例如volatile.

于 2010-09-27T04:05:44.400 回答