I'm trying to wrap my head around the wording but from what I think the
standard says:
1. it's impossible to swap a restrict pointer with another pointer,
i.e.
int a = 1, b = 2;
int * restrict ap = &a;
int * restrict bp = &b;
int *temp = bp;
This should require a cast, I believe.
bp = ap;
ap = bp;
is undefined.
Why do you think this is undefined? It might be, depending on what
you do with the pointers.
2. it doesn't support exactly overlapping memory, i.e.
void v3add(float * restrict a, float * restrict b)
{
a[0] += b[0];
a[1] += b[1];
a[2] += b[2];
}
float a[] = { 1, 2, 3 };
v3add(a, a);
The function itself is well defined, the call to the function is, I
suppose, technically undefined. Although there is no problem with
this actual use.
is undefined.
3. the library changes may break (correct?) existing code, i.e.
FILE *fopen(const char * restrict filename, const char * restrict
mode);
FILE *f = fopen("foo.rt", "rt");
if the compiler transforms this to:
static const char str[] = "foo.rt";
FILE *f = fopen(str, str + 4);
the code becomes undefined.
No, the code above is well-defined. In fact, it is possible that a
compiler might generate this code itself, as merging string literals
is allowed by the standard and some compilers do it.
The restrict qualifier only has meaning in terms of modifying an
object. That's why there is no problem at all with your third
example. The two strings passed to fopen() are const qualified and
the function does not try to modify them.
Your second example is not really undefined because even though
modifying objects pointed to by 'a' also modifies objects pointed to
by 'b', there is no use of the value of any object pointed to by 'b'
after it is modified by the write through 'a'.
Consider this version of your second example:
void v3add(float * restrict a, float * restrict b)
{
a[0] += b[0]; /* a[0] = b[0] = 2 */
a[1] += b[0]; /* a[1] = 2 + 2 = 3 */
a[2] += b[0]; /* a[1] =
}
int main()
{
float a[] = { 1, 2, 3 };
v3add(a, a);
/* printf() the values of 'a' */
return 0;
}
Without the 'restrict' keyword above, the compiler cannot assume that
'a' and 'b' point do not point to the same area. Specifically, they
can't assume that b[0] is not changed by any of the assignments
through 'a'. With the 'restrict' keyword it can assume, and generate
code based on that assumption. It is quite likely that the code will
actually read b[0] only once.
The concept of the restrict type qualifier is to inform the compiler
that the object(s) pointed to by a particular pointer will not be
modified other than through that pointer, or a pointer derived from
it.
Consider:
const int ci = 12;
void some_func(void)
{
some_global_function();
if (ci == 12)
{
printf("Yep, it's still 12\n");
}
}
....and:
void other_func(int restrict *ip)
{
*ip = 12;
some_global_function();
if (*ip == 12)
{
printf("Yep, it's still 12\n");
}
}
In both cases above, the compiler is justified in omitting the test
and making the printf() call unconditional.
This is true in the first place because it depends on the value of a
const object remaining the same.
In the second case, this is true because you have promised the
compiler, when you tell it its argument is restrict qualified, that
absolutely nothing that happens in the program will modify what ip
points to without doing so through ip.
This allows certain optimizations that would not be possible
otherwise, namely the compiler does not have to perform the test "if
(*ip == 12)". You have promised the compiler that whatever happens
during the call to "some_global_func()", the object(s) pointed to by
ip will not be modified.
If the object(s) pointed to by restrict qualified pointers are const,
or merely nothing attempts to modify them during the scope of a
restrict qualified pointer, they keyword has no meaning at all.
It is all about telling the compiler when it can assume that the
pointed to object(s) will not be changed without its knowledge.