1

文章提到

受限制的指针可以从一个复制到另一个以创建指针层次结构。但是,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,不是吗?根据我在本文开头引用的段落是不允许的吗?

4

1 回答 1

0

据我所知,该标准的作者首先决定他们想要restrict促进哪些优化,然后尝试编写将所有可以观察到这些优化的情况归类为未定义行为的规则。不幸的是,所写的规则最终比对允许优化的描述要复杂得多,同时无法以合理甚至有意义的方式处理极端情况。例如,标准定义“基于”的方式,表达式(p1 == p2) ? p3 : p4将是“基于” p1if p1==p2and 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 似乎试图利用标准中“限制”定义中的一些荒谬的极端情况,在标准甚至有点模棱两可的情况下,期望它们表现得明智是很危险的。

于 2020-01-10T23:05:43.803 回答