在某些情况下,您可以使用限制指针来访问同一个对象吗?
大多数限制的定义都说它是程序员对编译器的承诺,在指针的生命周期中,指针是访问对象的唯一方式。 这允许编译器优化输出,因为它知道它只能由一个指针访问,因此只能由它来改变。 如果我理解正确通常意味着程序不必重新加载指针指向的值。
如果这是正确的,那么当restrict关键字应该可用时应该有一些例外,即使它违背了应该如何使用它的意图。
我想到的一件事是指针指向的数据在指针的生命周期内从未实际发生过变化。 在这种情况下,即使指针指向同一位置,也不需要重新加载数据,因为它们在指针的生命周期中不会改变。 例如:
int max(int *restrict a, int *restrict b) { return((*a > *b) ? *a : *b); } int main(void) { int num = 3; int max = max(&num, &num); }
这是对限制的有效使用,即使它与它应该如何使用相反吗? 使用像这样的restrict关键字会导致未定义的行为吗?
正如埃里克在评论中所说,现在已经消失了, C99 draft standard
的关键短语6.7.3.1 Formal definition of restrict
是:
`If… X is also modified…`
6.7.3.1/10
的这个例子支持这种解释:
void h(int n, int * restrict p, int * restrict q, int * restrict r) { int i; for (i = 0; i < n; i++) p[i] = q[i] + r[i]; }
以及代码示例的以下注释:
说明了如何通过两个受限制的指针对未修改的对象进行别名化。 特别地,如果a和b是不相交的数组,则formsh(100,a,b,b)的调用已经定义了行为,因为在函数h内没有修改数组b。
所以看起来您的具体示例是defined behavior
因为您没有修改a
或b
。
您有时可以使用限制限定指针来访问与其他指针相同的对象,但仅限于未修改指向对象的情况。 以下是C 2011(N1570)6.7.3.1第1-3段和第4段的第一部分,其中散布着它们如何适用于问题中的代码。
6.7.3.1限制的正式定义
1设D是普通标识符的声明,它提供了一种将对象P指定为类型T的限制限定指针的方法。
所以int * restrict a
就是这样的声明D. 当使用max(&num, &num);
调用max(&num, &num);
,对象P是num
(或者更正式地说,是由num
命名的对象), T是int
。 同样, int * restrict b
是另一个这样的声明。
2如果D出现在块内并且没有存储类extern,则让B表示该块。 如果D出现在函数定义的参数声明列表中,则让B表示关联的块。 否则,让B表示main的块(或者在独立环境中的程序启动时调用任何函数的块)。
这些声明出现在函数定义的参数声明中,因此B是函数定义的块,即max
的主体。
3在下文中,指针表达式E被称为基于对象P if(在评估E之前执行B中的某个序列点)修改P以指向其先前的数组对象的副本指向会改变E.137的值。注意”based”仅针对具有指针类型的表达式定义。
函数max
包含指针表达式a
和b
,每次两次,因此这些都是指针表达式E的实例。 这些表达式分别取决于参数a
和b
,因为如果我们将a
更改为指向num
的副本而不是指向num
,则a
将具有不同的值(显然),并且类似于b
。 (虽然num
是一个标量对象,但它就像一个包含单个元素的数组,用于指针运算。)
4在每次执行B期间,让L为任何具有基于P的 L的左值。 如果L用于访问它指定的对象X的值,并且X也被修改(通过任何方式),则以下要求适用:…
在执行max
期间,左值*a
具有基于P ( a
)的地址( &*a
,即a
),因此左值*a
是L的实例。 此左值用于访问num
,因此num
是对象X的实例。 但是,在执行max
时, num
永远不会被修改。 因此,以下要求不适用。 类似地,左值*b
指的是在执行max
期间从不修改的对象( num
)。
因此, max
中的代码不违反restrict
要求,其行为由C标准定义。