Question

Most definitions of restrict say that it's a promise from the programmer to the compiler that for the lifetime of the pointer, the pointer is the only way that object is accessed. This allows the compiler to optimize the output, because it knows that it will be accessed only by one pointer and thus can be changed only by it. Which if I understand correctly usually means that the program doesn't have to reload the value the pointer points to.

If this is correct then there should be some exceptions when the restrict keyword should be usable even if it goes against the intent of how it should be used.

One thing that comes to mind would be when the data the pointer points to never actually changes during the lifetime of the pointer. In such case there is no need to reload the data even if the pointers point to the same location, because they don't change in the lifetime of the pointers. E.g.:

int max(int *restrict a, int *restrict b) {
  return((*a > *b) ? *a : *b);
}

int main(void) {
  int num = 3;
  int max = max(&num, &num);
}

Is this a valid use of restrict even though it goes against how it was supposed to be used? Will using the restrict keyword like this result in undefined behaviour?

Was it helpful?

Solution

As Eric says the in a comment that is now gone, the key phrase from the C99 draft standard 6.7.3.1 Formal definition of restrict is:

`If… X is also modified…`

this interpretation is supported by this example in 6.7.3.1/10:

void h(int n, int * restrict p, int * restrict q, int * restrict r)
{
  int i;
  for (i = 0; i < n; i++)
    p[i] = q[i] + r[i];
}

and the following comment with the code sample:

illustrate how an unmodified object can be aliased through two restricted pointers. In particular, if a and b are disjoint arrays, a call of the form h(100, a, b, b) has defined behavior, because array b is not modified within function h.

So it would seem that your specific example is defined behavior since you are not modifying a or b.

OTHER TIPS

You may sometimes use restrict-qualified pointers to access the same objects as other pointers, but only if the pointed-to objects are not modified. Here are C 2011 (N1570) 6.7.3.1 paragraphs 1-3 and the first part of paragraph 4 interspersed with how they apply to the code in the question.

6.7.3.1 Formal definition of restrict

1 Let D be a declaration of an ordinary identifier that provides a means of designating an object P as a restrict-qualified pointer to type T.

So int * restrict a is such a declaration D. When max is called with max(&num, &num);, the object P is num (or, more formally, the object named by num), and T is int. Similarly, int * restrict b is another such declaration.

2 If D appears inside a block and does not have storage class extern, let B denote the block. If D appears in the list of parameter declarations of a function definition, let B denote the associated block. Otherwise, let B denote the block of main (or the block of whatever function is called at program startup in a freestanding environment).

These declarations appear in the parameter declarations of a function definition, so B is the block of the function definition, that is, the body of max.

3 In what follows, a pointer expression E is said to be based on object P if (at some sequence point in the execution of B prior to the evaluation of E) modifying P to point to a copy of the array object into which it formerly pointed would change the value of E.137) Note that ‘‘based’’ is defined only for expressions with pointer types.

The function max contains pointer expressions a and b, twice each, so these are each an instance of a pointer expression E. These expressions depend on the parameters a and b, respectively, because if we changed a to point to a copy of num instead of pointing to num, then a would have a different value (obviously), and similarly for b. (Although num is a scalar object, it acts like an array containing a single element for purposes of pointer arithmetic.)

4 During each execution of B, let L be any lvalue that has &L based on P. 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:…

During the execution of max, the lvalue *a has its address (&*a, which is a) based on P (a), so the lvalue *a is an instance of L. This lvalue is used to access num, so num is an instance of an object X. However num is never modified during the execution of max. Therefore, the requirements that follow do not apply. Similarly the lvalue *b refers to an object (num) that is never modified during the execution of max.

Therefore, the code in max does not violate the requirements for restrict, and its behavior is defined by the C standard.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top