Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a pointer expression "based on" another pointer?

In Section 6.7.3.1 of the C language standard regarding restrict, it says:

  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.

  2. ...

  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.

I don't understand what this says - literally:

  • Who said P was pointing to a "copy of an array object"?
  • Why did P "formerly" point to anything? That is, who says we've changed its value?
  • Let's suppose E is a pointer of local scope. Why would modifying any pointer expression other than the E pointer itself "change the value of E"? It could change the value pointed to by E maybe. Right?

Can someone help me interpret that piece of text so as to make more sense?

(Inspired by this answer)

like image 563
einpoklum Avatar asked Oct 25 '25 11:10

einpoklum


1 Answers

The definition of "based on" is intended to define a transitive relation among pointers, but its actual wording would yield an unworkable definition which so far as I can tell doesn't match any actual compiler behavior.

It would be simpler to transitively apply the following rule (and this is what compilers seem to do): If *p is a pointer of type T*, the following pointers are "based on" p:

  • p+(intExpr) or p-(intExpr)
  • (otherType*)p
  • &*p
  • &p->structMemberofNonArrayType or &p->unionMemberofNonArrayType
  • p->structMemberofArrayType or p->unionMemberofArrayType
  • &p[intExpr]
  • Any pointer based on any of the above

I don't think the Standard is really clear about (someType*)someIntegerFunction((uintptr_t)p) and I don't think compiler writers are clear either.

Note that any q derived from p via any of the above expressions except the one involving casts through uintptr_t, the difference between (char*)p and (char*)q will be independent of the address held by p.

Incidentally, here's an example of a problematic corner case:

int test1(int * restrict p1, int * restrict p2, int n)
{
    int *restrict p3 = p1+n;
    // How would p4 and p5 be affected if p3 were replaced
    // with a pointer to a copy here?
    int *p4 = p3;
    if (p3 != p1) p4=p1;
    int *p5 = p2 + (p3 == p1);
    *p3 = 1;
    *p5 = 2;
    return *p4;
}

Using the transitive ways of forming a pointer based on another, if n is zero, p4 would clearly be based upon p3. Pointer p5 would not derive from p3, however, since there is no sequence of "based upon" steps by which its value could be derived.

Trying to apply the rules given in the Standard to the n==0 case by replacing p3 with a pointer to a copy of the array would not affect the value of p4, but would affect the value of p5. That would imply that p4 is not based upon p3, but p5 is, somehow.

I would regard such a result as nonsensical, and I think the authors of the Standard would too, but it follows from the rules given in the Standard, as worded.

like image 98
supercat Avatar answered Oct 27 '25 01:10

supercat



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!