Can someone give me a short example as how to best use this keyword in
your code?
This is my understanding: by definition restrict sounds like it is
suppose to restrict access to memory location(s) pointed to, so that
only one declared pointer can store that address and access the data in
those memory blocks, where I the data in those location(s) can be changed.
Is that a correct understanding?
Two examples why restrict is useful:
int calc_area (int* width, int* height) {
*width = 5;
*height = 6;
return (*width) * (*height);
}
int f (const int* p, int* q) {
int x = *p;
*q = x + 1;
return *p;
}
In the first function, you would assume that the function returns 30, so
an optimising compiler can avoid reading *width and *height and
multiplying these values. Sadly, this is wrong. If I write
int x;
int a = calc_area (&x, &x);
the result is 36, not 30. An optimising compiler is forced to store 5
into *width, then store 6 into *height, then read *width, then multiply
that value by 6 and return the result.
In the second function, you would assume that the value returned is
always equal to x. Sadly, this is wrong, too. If I write
int x = 5;
int a = f (&x, &x);
then x will be changed to 6, and the value returned is six, not five.
"const int* p" only means that you cannot store to the object *p through
the pointer *p itself, but the same object can be modified by other
means - for example by storing to *q.
In both functions, the compiler is forced to produce slow code, to
handle situations that will never arise in practice. That is what
"restrict" is for.
If you declare a restrict pointer object, like
int* restrict p;
then all pointer values from then on fall into two categories: Pointer
values that are derived from p, and pointer values that are not derived
from p. Roughly speaking, pointer values derived from p are pointer
values that are calculated by starting with p, and adding or subtracting
to it in arbitrary complicated way. For example,
int a [100];
int* restrict p = &a [0];
int* q = p + 1;
int* r = q - 1;
int* s = &a [0];
q and r are derived from p. s is not derived from p. Even though r == s,
one is derived from p, the other is not.
You promise the compiler two things:
1. Any object that is modified through a pointer based on p, is not
accessed or modified through any pointer that is not based on p.
2. Any object that is modified through a pointer that is not based on p,
is not accessed or modified through any pointer that is based on p.
Declaring a "const restrict" pointer object is stronger. If you have
const int* restrict p = &a[0];
for example, then your promise to the compiler is:
Any object that is accessed through a pointer based on p is not modified
by any means whatsoever.
What does that mean for the examples above: If you wrote
int calc_area (int* restrict width, int* restrict height) { ... }
you promise that assigning to *height does not change *width and vice
versa (just read the rules above carefully). Actually, using one
restrict pointer would have had the same effect. As a result, the
compiler can assume that the result of this function is always 30.
In the second function, if you wrote
int f (const int* restrict p, int* q) { ... }
you would promise to the compiler that *p is not modified in that
function by any means, so you promse that q does not point to *p. An
optimising compiler needs to read *p only once and knows that it cannot
change its value in that function.