vicencb
vicencb

Reputation: 303

Is restrict redundant for a const qualified pointer?

If we have for example f and g defined as:

void f(const int *restrict a, const int *restrict b, int *c){ ... }
void g(const int *         a, const int *         b, int *c){ ... }
  1. Assumming f and g have equivalent bodies, are they the same from the caller point of view?
  2. In the callee, can we make the same assumptions on the parameters?
  3. Has the compiler the same optimization opportunities?

If restrict is redundant I would expect all three answers to be yes.
Otherwise, why not?

Do not take into account bad programming practices like casting away the const qualifier.

Upvotes: 17

Views: 685

Answers (3)

M.M
M.M

Reputation: 141586

For this case:

void f(const int *restrict a, const int *restrict b, int *c)

restrict is not redundant. It means the compiler can assume that a and c do not alias. For example if the function body were:

int d = *a;
*c = 5;
d = *a;

then the compiler could remove the third line.


This is covered by C11 6.7.3/7:

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.

which is saying that if an object is accessed through a, then the object is not allowed to also be accessed via b or c.

The formal definition can be seen in C11 6.7.3.1/4 (Formal definition of restrict):

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

Here T is the declared type pointed to by a , i.e. const int, and L is *a, and X is whatever int that a and c are pointing to.

Upvotes: 4

Daniel Jour
Daniel Jour

Reputation: 16156

Has the compiler the same optimization opportunities?

If I understand the standard correctly, then the compiler has greater optimization opportunities with the version with restrict qualified pointers:

During each execution of B [some block of code], let L be any lvalue that has &L based on P [the restrict qualified pointer]. 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 [the type P points to] shall not be const-qualified. [..]

[N1570 §6.7.3.1/4, emphasis mine]

Logically speaking, if the object is modified, then the pointer to it shall not be const-qualified. Thus, if the pointer is const-qualified, the object may not be modified (by any means).

Xmodified Tconst !Tconst Xmodified -> !Tconst
true      true   false   false // oops, must disallow this case
true      false  true    true
false     true   false   true
false     false  true    true

Thus, if the compiler sees T const * restrict, then it can be sure that the object "behind" that pointer cannot be modified during the lifetime of that pointer. As such ...

Assumming f and g have equivalent bodies, are they the same from the caller point of view?

... this is a much stronger guarantee for the caller than just using T const *.

Upvotes: 0

Rufflewind
Rufflewind

Reputation: 8956

Do not take into account bad programming practices like casting away the const qualifier.

The problem is that even in standard C the presence of const on a pointer is not a binding contract. It is merely a suggestion to the programmer that the callee won't attempt to modify the pointee. The code is in fact permitted to modify the pointee (after casting) as long as the pointee was not originally declared as a const object.

Therefore, compilers are not able to use const safely: they still need to examine the contents of the callee to make sure that it isn't lying, if even possible.

Upvotes: 3

Related Questions