This has been hashed over many times here. Still some folks refuse to believe it. From K&R, 2nd Edition, Section 6.8: "… the results are implementation-dependent if something is stored as one type and extracted as another."
Obviously, not very portable.
Granted, we’re talking C++ here, not C. But, I believe the same caution applies.
IIRC, in C11, type punning using unions is allowed, in earlier versions, it’s not.
But like you said, Arduino uses C++ for its sketches, so C is irrelevant here.
In C++, it has never, and will never be allowed. It undermines the type system, is inconsistent with deterministic lifetimes specified by the C++ standard, and is much more confusing and error-prone than the correct way to type pun: using
This has been pointed out to GolamMostafa multiple times, but for some reason he keeps spreading the same misinformation.
In this case, you don’t even need special type punning constructs, the standard allows you to inspect the underlying representation of any type as an array of characters or bytes:
uint16_t value = 0x4321;
uint8_t *as_byte_array = reinterpret_cast<uint8_t *>(&value);
uint8_t lsb = as_byte_array;
uint8_t msb = as_byte_array;
This is both shorter and easier to understand than the (illegal) union approach. It is clear that the memory is being re-interpreted as an array of bytes.
As a first remark, I agree with aarg that the approach using bit shifts is preferable, because it handles things like Endianness correctly.
I want to stress that using
reinterpret_cast is only valid here because we’re casting to a character/byte type (
uint8_t). In almost every other circumstance, you are not allowed to use
reinterpret_cast for type punning.
Would it be reliable to create the int and byte array separately, then use memcpy to copy the int into the array?
Yes. That is in fact the only correct way to perform general type punning.
In C++20, you can use
std::bit_cast, which just calls
memcpy under the hood.