Ok, let’s get truly pedantic. After reading this, this and this, I’m pretty confident that I understand the intention behind both Standards.
So, doing reinterpret_cast
from std::uint8_t*
to char*
and then dereferencing the resulting pointer is safe and portable and is explicitly permitted by [basic.lval].
However, doing reinterpret_cast
from char*
to std::uint8_t*
and then dereferencing the resulting pointer is a violation of strict aliasing rule and is undefined behavior if std::uint8_t
is implemented as extended unsigned integer type.
However, there are two possible workarounds, first:
static_assert(std::is_same_v<std::uint8_t, char> ||
std::is_same_v<std::uint8_t, unsigned char>,
"This library requires std::uint8_t to be implemented as char or unsigned char.");
With this assert in place, your code will not compile on platforms on which it would result in undefined behavior otherwise.
Second:
std::memcpy(uint8buffer, charbuffer, size);
Cppreference says that std::memcpy
accesses objects as arrays of unsigned char
so it is safe and portable.
To reiterate, in order to be able to reinterpret_cast
between char*
and std::uint8_t*
and work with resulting pointers portably and safely in a 100% standard-conforming way, the following conditions must be true:
CHAR_BIT == 8
.std::uint8_t
is defined.std::uint8_t
is implemented aschar
orunsigned char
.
On a practical note, the above conditions are true on 99% of platforms and there is likely no platform on which the first 2 conditions are true while the 3rd one is false.