Restricted "circular references":
Originally, the question contained code that is guaranteed not to compile:
struct B;
struct A { struct B *restrict b1, b2; };
struct B { struct A *restrict a1, a2; };
The first structure is equivalent to:
struct A { struct B *restrict b1; struct B b2; };
and you cannot have an element that is an incomplete type (though you can have the restricted pointer to the incomplete type), so b2
is not valid.
This was pointed out and two possibilities were offered:
'Either':
struct B;
struct A { struct B *restrict b1, *restrict b2; };
struct B { struct A *restrict a1, *restrict a2; };
'Or':
struct B;
struct A { struct B *restrict b1; int b2; };
struct B { struct A *restrict a1; int a2; };
The 'either' option is what was intended, and what the question now lists.
The 'either' structures are syntactically valid but pretty much useless; you can create them, but they can't really hold anything useful in the way of information.
struct A a1, a2;
struct B b1, b2;
a1 = (struct A){ &b1, &b2 };
a2 = (struct A){ &b2, &b1 };
b1 = (struct B){ &a1, &a2 };
b2 = (struct B){ &a2, &a1 };
There really isn't very much you can do with those.
The 'or' structures are also syntactically valid and could have some use, though it is hard to see them being fantastically useful.
Assignment outer-to-inner:
Pass to function:
Pointer-arithmetic loop:
All three sets of functions are clean as far as I can tell.
Section 6.7.3 Type qualifiers of C11 (ISO/IEC 9899:2011) says:
8 An object that is accessed through a restrict-qualified pointer has a special association with that pointer. This association, defined in 6.7.3.1 below, requires that all accesses to that object use, directly or indirectly, the value of that particular pointer.135) The intended use of the restrict qualifier (like the register storage class) is to promote optimization, and deleting all instances of the qualifier from all preprocessing translation units composing a conforming program does not change its meaning (i.e., observable
behavior).
135) For example, a statement that assigns a value returned by malloc
to a single pointer establishes this
association between the allocated object and the pointer.
Section 6.7.3.1 Formal definition of restrict
says:
1 Let D
be a declaration of an ordinary identifier that provides a means of designating an object P
as a restrict-qualified pointer to type T
.
2 If D
appears inside a block and does not have storage class extern
, let B
denote the block. If D
appears in the list of parameter declarations of a function definition, let B
denote the associated block. Otherwise, let B
denote the block of main
(or the block of whatever function is called at program startup in a freestanding environment).
3 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
.137) Note that ‘‘based’’ is defined only for expressions with pointer types.
4 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: T
shall not be const-qualified. Every other lvalue used to access the value of X
shall also have its address based on P
. Every access that modifies X
shall be considered also to modify P
, for the purposes of this subclause. If P
is assigned the value of a pointer expression E
that is based on another restricted pointer object P2
, associated with block B2
, then either the execution of B2
shall begin before the execution of B
, or the execution of B2
shall end prior to the assignment. If these requirements are not met, then the behavior is undefined.
5 Here an execution of B
means that portion of the execution of the program that would correspond to the lifetime of an object with scalar type and automatic storage duration associated with B
.
137) In other words, E
depends on the value of P
itself rather than on the value of an object referenced indirectly through P
. For example, if identifier p
has type (int **restrict
), then the pointer expressions p
and p+1
are based on the restricted pointer object designated by p
, but the pointer expressions *p
and p[1]
are not.
That seems to allow the code you show. The pointer references are 'based on' the restricted pointers and that's allowed by that section.