受限制的指针问题

时间:2010-09-27 03:31:45

标签: c pointers c99 restrict-qualifier

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

  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();
    
  3. 谢谢! 安德鲁

2 个答案:

答案 0 :(得分:4)

作为参考,这里是restrict限定符的相当复杂的定义(来自C99 6.7.3.1“限制的正式定义”):

  让p成为普通人的宣言   提供手段的标识符   将对象P指定为   限制限定指针指向类型T.

     

如果D出现在一个区块内   没有存储类   extern,让B表示块。如果D   出现在参数列表中   函数的声明   定义,让B表示   相关块。否则,让B   表示主要块(或块)   任何函数的调用   程序启动独立式   环境)。

     

在下文中,指针   表达式E据说是基于   对象P if(在某个序列点   在执行B之前   评估E)将P修改为点   将数组对象的副本放入   以前指出的会改变   E的值。注意“基础”是   仅为表达式定义   指针类型。

     

在每次执行B期间,让L为   任何具有&amp; L基于P的左值。如果   L用于访问的值   它指定的对象X,X是   也修改(通过任何方式),然后   以下要求适用:T应   不是const限定的。所有其他   左值用于访问X的值   也应以其地址为基础   P.每次修改X的访问都应该   也被认为是修改P,for   本条款的目的。如果P.   被赋予指针的值   表达式E基于另一个   限制指针对象P2,   与块B2相关联,然后是   B2的执行应在之前开始   执行B,或者   B2的执行应在此之前结束   分配。如果这些   要求不符合,那么   行为未定义。

     

这里B的执行意味着   部分执行的   与...对应的程序   具有标量类型的对象的生命周期   和自动存储持续时间   与B相关联。

我对上述内容的阅读意味着,在您的第一个问题中,a无法分配到b,即使在“子”块内 - 结果也未定义。如果在“子块”中声明了b,则可以进行这样的分配,但由于b被声明为与a相同的范围,因此无法进行分配。

对于问题2,cd之间的分配也会导致未定义的行为(在这两种情况下)。

标准中的相关位(对于这两个问题)是:

  

如果为P赋值a   指针表达式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
    }
}

答案 1 :(得分:1)

restrict类型限定符是编译器的指示,如果修改了restrict - 限定指针所寻址的内存,则其他指针不会访问该内存记忆。编译器可以选择优化涉及restrict的代码 - 合格的指针,否则可能导致不正确的行为。 程序员有责任确保使用限制合格的指针,因为它们是打算使用的。否则,可能会导致未定义的行为。link

从上面的描述可以看出,你的任务都是非法的,可能在某些编译器生成的可执行文件中有效,但在其他编译器中则有效。不要指望编译器本身发出错误或警告,因为restrict只是提供了执行某些优化的机会,它可以选择不执行,例如volatile