17

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.

vicencb
  • 303
  • 1
  • 6
  • 1
    `restrict` is a challenging type qualifier to understand and has subtle impacts. Recommend avoid selecting an answer quickly. (disclosure I do has an answer below), as I am seriously interested in seeing others' answers on this intriguing post. (Kudos for a trending question by a new guy) โ€“ chux - Reinstate Monica Oct 06 '16 at 22:58
  • Possible duplicate of [Does restrict help in C if a pointer is already marked const?](http://stackoverflow.com/questions/457441/does-restrict-help-in-c-if-a-pointer-is-already-marked-const) โ€“ Raedwald Jan 18 '17 at 09:50
  • Indeed, duplicate. It would be a new and better question if the question asked whether `const` is redundant in: `int* const restrict a` โ€“ Bart Aug 25 '21 at 08:52

3 Answers3

4

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.

M.M
  • 138,810
  • 21
  • 208
  • 365
3

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.

Rufflewind
  • 8,545
  • 2
  • 35
  • 55
0

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 *.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63