首页 > 解决方案 > 将限制指针分配给非限制指针的语义是什么?

问题描述

以下假设代码是否正确(注释中的假设是否成立)?还是有UB?

#define N 1 // what if it's 0?

void foo(int *x, int * restrict y) {
  *x = 42;
  *y = 0;
  // compiler can assume *x is still 42.
  {
    int *a = y + N;
    *a = 123;
    // compiler can no longer assume *x is 42.
  } // does the new scope matter in this case?
}

标签: clanguage-lawyerrestrict-qualifier

解决方案


// compiler can no longer assume *x is 42.

我认为这种说法没有根据。

// does the new scope matter in this case?

不,restrict 的规则涵盖块B,对于在函数参数中声明的限制限定指针,它是定义函数的块。该块 B 中的该块B的一部分。

的定义restrict在 C 2018 6.7.3.1 中给出。第 1 段说:

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

int * restrict y是普通标识符“<code>y”的声明Dy ,并指定对象Pint ,它是指向(类型T )的限制限定指针。

第 2 段说:

...如果D出现在函数定义的参数声明列表中,让B表示关联的块...</p>

所以B是定义函数的块。

第 3 段说:

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

所以,之后int *a = y + N;,a是基于y因为y在此初始化之前修改a会更改 的值a,即使y更改为指向数组的副本。

第 4 段说:

在每次执行B期间,令L为基于P具有&L的任何左值。如果L用于访问它指定的对象X的值,并且X也被修改(以任何方式),则适用以下要求: ... 用于访问X值的每个其他左值也应基于其地址在P上……</p>

*a是一个具有&L基于的左值L,因为是,我们知道是基于。y&*aaay

然后,在 中*a = 123;,这个L用于访问它指定的对象,并且该对象被修改。所以要求必须适用:用于访问对象的每个其他左值也应基于y.

所以,如果*x还访问了 指定的对象*a,那就违反了上面的要求,因为&*x不是基于y. x作为单独的参数传递,更改 的值y不会更改 的值x,因此x&*x不基于y

由于编译器有权期望满足要求,因此它可能会假设*a = 123;不会改变*x


推荐阅读