Is the following valid usage of restrict qualifier in C or undefined behaviour?
#include <stdio.h>
int foo(float * restrict a) {
float a1 = *a;
float a2 = *(a+1);
float * restrict c = a;
*c = 1;
*(c+1) = 2;
// are compilers obliged to load a[0] and a[1] again?
printf("%f %f\n",*a,*(a+1));
printf("%p %p\n", (void *)a1, (void *)a2);
}
restrict
qualifier of a
is not being violated.The restrict
qualifier of a
does not disallow to modify the array through c
instead of a
, because the value of c
depends on the value of a
. So you are indirectly modifying the array through a
, which is permissible as far as the restrict
qualifier of a
is concerned.
restrict
qualifier of c
is being violated.§6.7.4.2 ¶4 of the ISO C23 standard states the following:
During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: [...] Every other lvalue used to access the value of X shall also have its address based on P.
In that quote,
restrict
pointer declaration, or the entire function block in the case of a parameter being declared with the restrict
qualifier,The sentence
Every other lvalue used to access the value of X shall also have its address based on P.
is being violated, because in the line
printf("%f %f\n",*a,*(a+1));
the referenced object X is being accessed through a
, and a
does not depend on c
(c
depends on a
, but not vice versa).
The terms "depends on" and "based on" are being used by me synonymously. The ISO C23 standard only uses the term "based on", and defines this term in §6.7.4.2 ¶3 the following way:
In what follows, a pointer expression E is said to be based on object P if (at some sequence point in the execution of B prior to the evaluation of E) modifying P to point to a copy of the array object into which it formerly pointed would change the value of E.
Since the restrict
qualifier of c
is being violated, the posted code has undefined behavior. Had only a
been declared with the restrict
qualifier and c
been declared without that qualifier, then the program's behavior would have been well-defined.
The previous statement is based on the assumption that a
points to an array of float
with at least two elements. If that is not the case, then the program's behavior would also be undefined in the case specified above.