1

Excerpt from the book "C++ memory management" by Patrice Roy

For example, the following code is correct, albeit not something one should seek to do (it makes no sense, and it does things in unnecessarily complicated ways, but it’s legal and does no harm):

struct A {
   int a;
   short s;
};

short * f(A &a) {
    // pointer interconvertibility in action!
    int *p = reinterpret_cast<int*>(&a);
    p++;
    return reinterpret_cast<short*>(p); // Ok, within the
                                       // same object
}

int main() {
    A a;
    short *p = f(a);
    *p = 3; // fine, technically
}

Author does not elaborate this statement. Is it correct from standard point of view and under what condition if so ?

8
  • Why use &a in the reinterpret_cast, when a is already a pointer? Should it be reinterpret_cast<int *>(a)? Commented May 30 at 22:02
  • 1
    a is a reference Commented May 30 at 22:04
  • 10
    The code is not legal. There can be padding between a and s so at best it's implementation defined. Commented May 30 at 22:09
  • 2
    It's not !00% kosher, but what Roy seems to be getting at is C++ doesn't really care what address a pointer points at so long as the type of the object at that pointer matches the type you say it is. Here Roy took a pointer to an int advanced the address by one int where, baring unusual behaviour, a short sits. Since the pointed-at object is a short and will, thanks to the reinterpret_cast be used as a short it's all good. Unfortunately C++ doesn't guarantee that s will be immediately after a in memory. For example, how would a 24-bit short be aligned after a 32 bit int? Commented May 30 at 22:41
  • 3
    This code would only work if the short existed immediately behind the int in memory (ie, no padding existed), but this code does not guarantee that. The proper way to get a valid pointer to the short using pointer arithmetic would be something like this instead: char *p = reinterpret_cast<char*>(&a); p += offsetof(A, s); return reinterpret_cast<short*>(p); Commented May 31 at 0:29

1 Answer 1

1

I believe this is incorrect. Assuming for argument's sake that size and alignment and padding work out, which aren't checked, there is still a violation of pointer rules.

reinterpret_cast between A* and int* works by the rules of pointer interconvertibility, and given a pointer to an A object, one can obtain a pointer to the int object which is its first member.

So p is a valid pointer to an object basic.compound

By expr.add, ++p results in a pointer "past the end" of the int member. Therefore, it represents the "first byte in memory after the end of the storage occupied by the object" but it does not point at the short. With the assumption that the address is the address of the short, we can try to get a pointer through std::launder. ptr.launder

std::launder(reinterpret_cast<short*>(p))

But this requires that all bytes reachable through the result are reachable through the initial pointer, which is not the case. basic.compound

Therefore, the example is illegal.

Sign up to request clarification or add additional context in comments.

2 Comments

launder reachability requirement is not satisfied
Oh my, good catch. Check the edit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.