重叠指针,类型的限制限定符的粒度

restrict全部要点是承诺通过一个指针访问不要别名。 也就是说,有些例子表明重叠的内存地址不会暗示别名。 例如:

 int* arr_ptr0 = &arr[0]; int* arr_ptr1 = &arr[1]; for (int i=0;i<10;++i) { *arr_ptr0 = *arr_ptr1; arr_ptr0 += 2; arr_ptr1 += 2; } 

问题是,这些指针确实指向重叠的内存! 对于这个特定的例子,像这样的指南说,例如:

这是有效的。 。 。 指向同一个数组对象,前提是通过其中一个指针访问的元素范围与通过另一个指针访问的元素范围不重叠。

我的问题是: 什么粒度是“元素”?

例如,假设我有一个struct Foo类型的数组。 我是否真的需要确保我不会访问相同范围的元素( Foo ),即使我访问的部分是不相交的? 这是一个简单的标量示例:

 struct Foo { int i; float f; }; void f(struct Foo*restrict foo0, struct Foo*restrict foo1) { foo0->i = 6; foo1->f = 19.0f; } void g(struct Foo* foo) { f(foo,foo); /* problem? */ } 

您可以通过指向不同类型的指针(例如charint )遇到类似的问题,但上面的结构示例可能更清楚。

该标准的相关文本是6.7.3.1限制的正式定义

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

2如果D出现在块内并且没有存储类extern,则让B表示该块。 如果D出现在函数定义的参数声明列表中,则让B表示关联的块。 否则,让B表示main的块(或者在独立环境中的程序启动时调用任何函数的块)。

3在下文中,指针表达式E被称为基于对象P if(在评估E之前执行B中的某个序列点)修改P以指向其先前的数组对象的副本指向会改变E.137的值。注意”based”仅针对具有指针类型的表达式定义。

4在每次执行B期间,让L为任何具有&L基于P的左值。如果L用于访问它指定的对象X的值,并且X也被修改(通过任何方式),则以下要求apply:T不具备const限定条件。 用于访问X值的每个其他左值也应具有基于P的地址。出于本子条款的目的,每次修改X的访问也应被视为修改P. 如果P被赋予指针表达式E的值,该指针表达式E基于与块B2相关联的另一个受限指针对象P2,则B2的执行应在执行B之前开始,或者B2的执行应在该执行之前结束。分配。 如果不满足这些要求,则行为未定义。

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

您的第一个示例(交错数组)完全有效,我阅读标准。

结构的第二个例子不太清楚,并且取决于是否使用->运算符(你写的.但意思是-> )与foo0 (或foo1 )意味着*foo0 (或foo1 )是“用于访问它指定的对象的值“。 这个我不清楚,因为结构不用作值; 只有它的成员。

restrict关键字严格地告知编译器,应用程序不会在类型限定范围内通过另一个不是从它派生的指针修改相同的地址。

但是,没有什么能够限制应用程序这样做。 但是,可以安全地假设修改通过restrict限定指针访问的地址,而不是restrict合格指针将导致未定义的行为(当心龙)。