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;
}
问题是,这些指针实际上做指向重叠的内存!对于这个特定的例子,像this这样的指南说,例如:
有效。 。 。指向同一个数组对象,前提是通过其中一个指针访问的元素范围与通过另一个指针访问的元素范围不重叠。
我的问题是:什么粒度是&#34;元素&#34;?
例如,假设我有一个struct Foo
类型的数组。我是否真的需要确保我不会访问相同范围的元素(Foo
s),即使我访问的部分是不相交的?这是一个简单的标量示例:
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? */
}
您可以通过指向不同类型的指针遇到类似问题(例如char
与int
),但上面的结构示例可能更清晰。
答案 0 :(得分:1)
标准的相关文本是 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为基于P的具有&amp; L的左值。如果L用于访问它指定的对象X的值,则X也被修改(以任何方式) ,则以下要求适用:T不应符合要求。用于访问X值的每个其他左值也应具有基于P的地址。出于本子条款的目的,每次修改X的访问也应被视为修改P.如果为P分配了指针表达式E的值,该指针表达式E基于与块B2相关联的另一个受限指针对象P2,则B2的执行应在执行B之前开始,或者B2的执行应在该执行之前结束。分配。如果不满足这些要求,则行为未定义。
5这里执行B意味着程序执行的一部分将对应于具有标量类型的对象的生命周期和与B关联的自动存储持续时间。
我的第一个例子(交错数组)完全有效,我阅读标准。
第二个带结构的示例不太清楚,取决于->
运算符(您的.
编写但->
}与foo0
的使用情况)(或foo1
)表示*foo0
(或foo1
)“用于访问其指定的对象的值”。这个我不清楚,因为结构不用作值;只有它的成员。
答案 1 :(得分:-1)
restrict
关键字是编译器的严格建议,应用程序不会在类型限定范围内通过另一个不是从它派生的指针修改相同的地址。
但实际上并没有限制应用程序这样做。但是,可以安全地假设修改通过restrict
限定指针通过restrict
限定指针以外的其他方式访问的地址将导致 undefined 行为(小心龙)。