Consider these two functions:
void foo(char * __restrict localPtr)
{
// some work with localPtr
}
void bar(char * __restrict ptr)
{
// some work with ptr
foo(_ptr);
// some other work with ptr
}
As ptr
has been declared __restrict
in bar
, is calling foo()
dangerous? By dangerous, I mean that the memory zone pointed by localPtr
overlaps ptr
's one. What are the guidelines about that?
The restrict
qualifier means that the only way for the called function to access the memory passed as localPtr
in foo
is via that pointer; there are no aliases to that memory. This might enable the optimizer to produce better code because it doesn't have to worry about another pointer also changing the data.
In this context, and in most others, the restrict
qualifier places an onus on you, the programmer making the calls, to ensure that you are honouring the 'no aliases' requirement.
There is no visible danger from the code above.
Note that most usually you have multiple pointers in the argument list when restrict
is used. From the C standard, compare:
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
The first (memcpy()
) says that the chunks of memory [s1 .. s1+n-1]
and [s2 .. s2+n-1]
must not overlap; you will get undefined behaviour if they do in fact overlap. The second (memmove()
) does not impose that requirement.
But isn’t the call to
foo()
creating another pointer that is changing the data?
Yes, No, Sort Of ... but mostly No.
The pointer in foo()
is certainly passed to bar()
, but while bar()
is running, the only way bar()
can get at the memory is through the pointer it was passed. Thus bar()
is able to be compiled on the assumption that it has no alias for the memory it is working with.
When the compiler is processing foo()
, it knows (ensures) that there is a sequence point after the arguments to bar()
are evaluated and before the function is called, and another when the function returns. It knows that the data might have been modified by bar()
since it was not passed a const char *
. Therefore, it will generate the code to account for these possibilities. However, the compiler also knows that the only way that foo()
can access the memory addressed by localPtr
is via localPtr
(that's what the restrict
says), and it can proceed based on that assumption.
So, there is a second copy of the pointer while bar()
is being called, but it is not in violation of the rules of restrict
in any way.