---
The function parameter declarations in the following example
void f(int n int * restrict p int * restrict q) { while (n-- > 0) *p++ = *q++; }
assert that during each execution of the function if an object is accessed through one of the pointer parameters then it is not also accessed through the other.
---
Note that the notion of any offset of a pointer p
being separated from everything else that is not also an offset of p
is a relative notion. In the absolute p
has to point somewhere. If for instance p
points inside a global array t
then p
aliases with t
. The restrict
qualifier only means that locally inside the function f
for what f
does an offset of p
does not alias with any lvalue not based on p
. As the next paragraph in the standard puts it:
---
The benefit of the restrict
qualifiers is that they enable a translator to make an effective dependence analysis of function f
without examining any of the calls of f in the program. The cost is that the programmer has to examine all of those calls to ensure that none give undefined behavior. For example the second call of f
in g
has undefined behavior because each of d[1]
through d[49]
is accessed through both p
and q
.
void g(void) { extern int d[100]; f(50 d + 50 d); //valid f(50 d + 1 d); //undefined behavior }
---
The call f(50 d + 50 d)
is valid because although offsets of d+50
can obviously alias with offsets of d
they do not alias inside the function for what the function does. When calling f(50 d + 1 d);
offsets of the two restrict
-qualified pointers do alias and the call invokes undefined behavior.
And this sums up why restrict
alone would not be good for modular reasoning about programs. It is part of the prototype and the prototype is a kind of limited contract but the exact meaning of restrict
depends on the function's implementation. If the function computes p + 49
then p + 49
is part of the offsets of p
that must not alias with the rest of the memory locations accessed by f
. If f
accesses the global variable G
by name then p
must not point to G
. if f
does not access G
by name then p
is allowed to point to G
. It is only one particular implementation of f
that gives meaning to restrict
.
By contrast a proper contract is supposed to be self-contained. The ACSL precondition \separated(p+(0..n-1) q+(0..n-1));
tells the programmer exactly how the arguments p
and q
are allowed to alias. An implementation for f
needs not exist for the programmer to start using it with the confidence that ey is calling f
properly.