【问题标题】:Restriction on child pointer of a restricted pointer?对受限指针的子指针的限制?
【发布时间】:2020-04-15 15:59:25
【问题描述】:

article 提到:

可以将受限制的指针从一个复制到另一个以创建指针层次结构。但是,C99 标准中定义了一个限制。子指针不得与父指针位于同一块级范围内。在同一块级范围内复制受限指针的结果是未定义的。

然后它提供了一个例子:

{
  vector3* restrict position   = &obj_a->position;
  float*   restrict position_x = &position->x; <-- UNDEFINED
  {
    float* restrict position_y = &position->y; <-- VALID
  }
}

不过,后面还有一个例子:

void
move( vector3* restrict velocity, 
      vector3* restrict position, 
      vector3* restrict acceleration, 
      float             time_step,  
      size_t            count, 
      size_t            stride )
{
  float* restrict acceleration_x = &acceleration->x;
  float* restrict velocity_x     = &velocity->x;
  float* restrict position_x     = &position->x;

我认为现在受限父指针position 与其子指针position_x 在同一范围内,不是吗?根据我在这篇文章开头引用的段落是不允许的吗?

【问题讨论】:

    标签: c gcc c99 restrict-qualifier


    【解决方案1】:

    据我所知,该标准的作者首先决定他们希望restrict 促进哪些优化,然后尝试编写将所有可观察到这些优化的情况归类为未定义行为的规则。 不幸的是,所写的规则最终比对允许优化的描述要复杂得多,同时无法以合理甚至有意义的方式处理极端情况。例如,标准定义“基于”的方式,如果p1==p2p3!=p4 则表达式(p1 == p2) ? p3 : p4 将是“基于”p3!=p4,因为用指向相同数据的指针替换p1 会改变表达式的值。更奇怪的是,标准可能会被解释为(clang 和 gcc 以这种方式解释它!)说左值表达式 p[1] 并不总是基于 p

    如果不是查看“允许”执行哪些程序,而是根据排序来描述restrict 的实现,那将简化事情。使用左值的操作至少可能派生自restrict 限定指针并在其生命周期内发生,相对于彼此以及该生命周期的开始和结束进行排序,在其生命周期中使用左值发生的操作可能不会从它派生出来的序列是相对于彼此以及相对于该生命周期的开始和结束进行排序的,但是两组中的操作可以任意交错。如果在同一个块中声明了两个指针,则它们的生命周期的结束没有顺序,那么编译器给出:

    void test(int *p)
    {
      int * restrict p1 = p;
      *p1 = 1;
      int * restrict p2 = p1;
      *p2 = 2;
    }
    

    可以转换成:

    void test(int *p)
    {
      // Start lifetime of p1
      int p1_temp = *p; // Copy everything that will be accessed via p1
      int * restrict p1 = &p1_temp;
    
      *p1 = 1;
    
      // Start lifetime of p2
      int p2_temp = *p1; // Copy everything that will be accessed via p2
      int * restrict p2 = &p2_temp;
    
      *p2 = 2;
    
      // End lifetime of p2
      *p1 = p2_temp; // Copy data back to *p1
    
      // End lifetime of p1
      *p = p1_temp; // Copy data back to *p
    }
    

    这可行,但由于 p1 和 p2 的生命周期的结束没有顺序,最后两条语句可能会被转置,从而破坏代码。

    我认为这里标准的意图是函数参数的生命周期超过任何其他自动对象的生命周期,有效地表现得好像这些对象在嵌套块中。然而,鉴于 clang 和 gcc 似乎试图利用标准中“限制”定义中的一些荒谬的极端情况,在标准甚至有点模棱两可的情况下,期望它们表现得明智是很危险的。

    【讨论】:

    • 感谢您分享您的想法。我认为您的示例具有未定义的行为,因为 int * restrict p1int * restrict p2 意味着它们没有别名为任何整数。因此,这意味着 p1、p2 和 p 不能指向同一个内存位置。没有?
    • @HCSF:需要的是,在p2 的生命周期内,它访问的事物集或基于它的指针与通过其他方式访问的事物集脱节。如果p2 在内部块中,则不会有问题。我认为通过说对象的生命周期以相反的声明顺序结束,并且当restrict-qualified 指针首次获得值时,让标准适应上述构造应该没有任何问题,但是restrict 的“正式”定义相当草率,而且这个...
    • ...与其他问题相比,问题很小,例如左值p[1] 并不总是基于p
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-13
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多