void f(int * restrict p, int * restrict q, int * restrict r);
由于我们不知道指针将如何被访问,因此即使我们传递相同的指针(就像6.7.3.1.10中的示例所解释的那样),我们也无法确定调用是否会触发未定义行为。
因此,在这些情况下,除非我们对函数有更多了解,否则The function parameter declarations:
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]; }
illustrate how an unmodified object can be aliased through two restricted pointers. In particular, if
a
andb
are disjoint arrays, a call of the formh(100, a, b, b)
has defined behavior, because arrayb
is not modified within functionh
.
restrict
是多余的,只是用作对调用者的提示/注释。
例如,让我们来看一下标准库中的
sprintf
(7.21.6.6)。
Synopsis
#include <stdio.h> int sprintf(char * restrict s, const char * restrict format, ...);
Description
The
sprintf
function is equivalent tofprintf
, except that the output is written into an array (specified by the arguments
) rather than to a stream. (...)
从简介和描述的第一句话中,我们知道s
将被写入,并且s
是一个受限指针。因此,我们可以假设(无需继续阅读)会出现以下调用:
char s[4];
sprintf(s, "%s", s);
会触发未定义行为吗?
如果是,则:即使澄清,
sprintf
描述的最后一句话是否多余?如果在重叠对象之间进行复制,行为未定义。
如果不是,则相反:
restrict
限定符是否多余,因为描述实际上让我们知道将会出现未定义的行为?
memcpy
行为完全相同且具有相同restrict
限定符的函数,但仍然处理重叠情况而不会引发未定义行为。关键在于使用循环检查范围内所有索引处的src+i==dest
或dest+i==src
(无论指针是否标识同一对象的部分),这是已定义的行为。如果存在任何一个i
使得其中一个等式成立,则memmove(dest, (char*)dest+((char*)dest-(char*)src), n)
将具有已定义的行为。由于访问将使用从dest
派生的地址,因此不会... - supercatrestrict
的要求。有些情况下,知道一个函数的定义在参数上同时包含const
和restrict
可能会允许调用方进行优化,否则是不可能的,但原型中存在restrict
并不意味着它对定义具有约束力。 - supercat