Is reinterpret_cast<char*>(myTypePtr) assumed to point to an array?
Asked Answered
F

2

0

We know that char* can alias anything: According to cppreference

Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true: [...] AliasedType is std::byte, char, or unsigned char: this permits examination of the object representation of any object as an array of bytes. [...]

The statement in boldface is not present in n4659 draft [6.10, (8.8)]. Since doing pointer arithmetic on pointers that don't point to elements of the same array is undefined, can we really access bytes other than the first one using only reinterpret_cast? Or maybe std::memcpy must be used for that purpose?

Fernand answered 1/7, 2020 at 12:4 Comment(12)
Possible duplicate of #62329508 TL;DR: If you interpret the standard literally, it seems to not be allowed, but it looks like a standard defect. Any half-decent compiler shouldn't have any problems with it.Pilfer
@Pilfer Thanks, that's indeed a closely related question.Fernand
can we really access bytes other than the first one You can't access even the first one.Superfine
@LanguageLawyer I just read your comment from the chat linked by HolyBlackCat, where you said the same thing. I guess you mean that the pointer `value' (whatever it is) is not changed by reinterpret_cast. But nonetheless, the last point of [basic.lval] that I mentioned in my question seems to imply that accesing this byte is NOT undefined. So what do you want to say exactly?Fernand
[basic.lval] that I mentioned in my question seems to imply that accesing this byte is NOT undefined No, it doesn't say that. It says if you access the object through a glvalue of type other than X, Y, Z, the behavior will definitely be undefined. But this doesn't guarantee that it will definitely be defined if you access the object through a glvalue of type X, Y, or Z. !p → !q doesn't follow from p → q.Superfine
And it also doesn't guarantee that what you will be accessing has anything to do with "bytes". What you'll be accessing is the object itself.Superfine
@LanguageLawyer Wow! You are right, although p->q is equivalent with !q->!p. The point is that !p -> !q is not.Fernand
@LanguageLawyer I see that you interpret the standard literally, and this is probably the only right way to do this. So one last question: Does copying an object into an array of chars with std::memcpy give me an access to individual bytes?Fernand
std::memcpy give me an access to individual bytes? IDKSuperfine
@LanguageLawyer OK, thanks a lot for all explanations.Fernand
@Fernand "std::memcpy give me an access to individual bytes" Yes, [basic.types]/2. Note that it doesn't say that std::memcpy must be used, but only uses it in the example. (Which I take as a yet another sign that the intention was to allow copying the bytes by any means, not only memcpy.)Pilfer
@Pilfer Thanks again!Fernand
R
3
auto ptr = reinterpret_cast<char*>(myTypePtr);

The standard permit this conversion, due to:

An object pointer can be explicitly converted to an object pointer of a different type.73 When a prvalue v of object pointer type is converted to the object pointer type “pointer to cv T”, the result is static_­cast<cv T*>(static_­cast<cv void*>(v)). [ Note: Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value.  — end note ]

So, the conversion is equivalent to:

assume myTypePtr has no any cv qualifier.

auto ptr = static_­cast<char*>(static_­cast<void*>(myTypePtr))

And you are permitted to dereference myTypePtr to access the value within the object(the pointer point to), due to:

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • a char, unsigned char, or std​::​byte type.

If myTypePtr is not an object of array of char type, as long as you applied addition to ptr, It will result in undefined behavior, due to:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the expression P points to element x[i] of an array object x with n elements,86 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) element x[j + p] if 0 ≤ i+j≤n ; otherwise, the behavior is undefined. Likewise, the expression P - J points to the (possibly-hypothetical) element x[i - j] if 0 ≤ i - j≤n ; otherwise, the behavior is undefined.

For addition or subtraction, if the expressions P or Q have type “pointer to cv T”, where T and the array element type are not similar, the behavior is undefined.

Because the element of myTypePtr is not of type char. Hence applying addition to ptr result in undefined behavior.


Or maybe std::memcpy must be used for that purpose?

Yes, If the object to which myTypePtr point subject to the following rules:

For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes ([intro.memory]) making up the object can be copied into an array of char, unsigned char, or std​::​byte ([cstddef.syn]).43 If the content of that array is copied back into the object, the object shall subsequently hold its original value.

OR

For any trivially copyable type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the underlying bytes ([intro.memory]) making up obj1 are copied into obj2,44 obj2 shall subsequently hold the same value as obj1.

However, It's unfortunately we can't implement such a memcpy subject to the current standard.

Rocca answered 2/7, 2020 at 8:53 Comment(1)
Comments are not for extended discussion; this conversation has been moved to chat.Mathura
B
1

As std::as_bytes and std::as_writable_bytes essentially depend on such usage (which is specified in [span.objectrep]), I guess we can assume it is supported, even though it is not true according to C++17/20 (and the latest working draft).

This defect has been revealed by P1839, and, unfortunately, has not been resolved yet.

Bertine answered 22/12, 2021 at 8:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.