大多数限制的定义都说它是程序员对编译器的承诺,在指针的生命周期中,指针是访问对象的唯一方式。这允许编译器优化输出,因为它知道它只能被一个指针访问,因此只能由它来改变。如果我理解正确通常意味着程序不必重新加载指针指向的值。
如果这是正确的,那么当restrict关键字应该可用时,即使它违背了应该如何使用它的意图,也应该有一些例外。
我想到的一件事是指针指向的数据在指针的生命周期内从未实际发生过变化。在这种情况下,即使指针指向同一位置也不需要重新加载数据,因为它们在指针的生命周期中不会改变。 E.g:
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关键字会导致未定义的行为吗?
答案 0 :(得分:3)
正如Eric在评论中所说的那样,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是不相交的数组,则调用形式为h(100,a,b,b)的行为已定义,因为数组b未在函数h中修改。
因此,您的具体示例似乎是defined behavior
,因为您没有修改a
或b
。
答案 1 :(得分:3)
有时,您可以使用限制限定指针来访问与其他指针相同的对象,但前提是未修改指向的对象。以下是C 2011(N1570)6.7.3.1第1-3段和第4段的第一部分,其中插入了它们如何适用于问题中的代码。
6.7.3.1限制的正式定义
1让 D 成为普通标识符的声明,它提供了一种指定对象 P 作为限制限定指针的方法 T 强>
所以int * restrict a
是一个声明 D 。使用max
调用max(&num, &num);
时,对象 P 为num
(或者更正式地称为num
指定的对象),< strong> T 是int
。同样,int * restrict b
是另一个这样的声明。
2如果 D 出现在块内并且没有存储类extern,请让 B 表示该块。如果 D 出现在函数定义的参数声明列表中,请让 B 表示关联的块。否则,让 B 表示 main 的块(或者在独立环境中的程序启动时调用任何函数的块)。
这些声明出现在函数定义的参数声明中,因此 B 是函数定义的块,即max
的正文。
3在下文中,指针表达式 E 被认为是基于对象 P if(在执行 B的某个序列点在评估 E 之前修改 P 以指向其先前指向的数组对象的副本将更改E.137的值。注意''based''仅针对具有指针类型的表达式定义。
函数max
包含指针表达式a
和b
,每次两次,因此这些都是指针表达式 E 的实例。这些表达式分别取决于参数a
和b
,因为如果我们将a
更改为指向num
的副本而不是指向num
,那么a
将具有不同的值(显然),对b
也是如此。 (虽然num
是一个标量对象,但它就像一个包含单个元素的数组,用于指针运算。)
4在每次执行 B 期间,让 L 为基于 P &amp; L 的任何左值>。如果 L 用于访问其指定的对象 X 的值,并且 X 也会被修改(无论如何),那么以下要求适用:......
在执行max
期间,左值*a
的地址(&*a
,a
)基于 P ({ {1}}),因此左值a
是 L 的实例。此左值用于访问*a
,因此num
是对象 X 的实例。但是,在num
执行期间永远不会修改num
。因此,以下要求不适用。同样地,左值max
指的是在*b
执行期间从未修改过的对象(num
)。
因此,max
中的代码不违反max
的要求,其行为由C标准定义。