Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Is `uint8_t` always an alias for a character type if it exists?
Is uint8_t
guaranteed to be a character type if it exists? Will using a uint8_t*
to examine bytes of an object cause violation of the strict aliasing rule? Is the following legal code:
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <string>
int main() {
std::string str{"Hello"};
std::uint8_t* p = reinterpret_cast<std::uint8_t*>(&str);
for (std::size_t i = 0; i < sizeof str; ++i) {
std::printf("%d\n", *p++);
}
}
1 answer
Yes, it is in practice always a character type and you can safely assume as much, both in terms of (g)lvalue access and in terms of strict pointer aliasing. If not, the compiler would soon render itself completely useless.
C and C++ both got the following rule (C17 7.20.1.1/3)
intN_t
...uintN_t
...These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two’s complement representation, it shall define the corresponding typedef names.
So if your system supports 8 bit 2's complement numbers, it must support uint8_t
. No exceptions - not even for freestanding (embedded) systems - stdint.h
is one of the mandatory headers for all conforming implementations (C17 4/6).
And for such a system it does not make sense to define unsigned char
as anything else but 8 bits. CHAR_BITS
will be 8.
Padding bits, trap representations and other such exotic oddities is not allowed for character types either, nor can trap representations exist in 2's complement integers.
In practice, all known real-world compilers will simply implement uint8_t
as a typedef
for unsigned char
. You can easily prove this by trial and error:
C
_Generic((uint8_t){0}, uint8_t:0, unsigned char:0);
error: '_Generic' specifies two compatible types
C++
void f (unsigned char c){}
void f (uint8_t c){}
error: redefinition of
void f(uint8_t)
note:void f(unsigned char)
previously defined herevoid f (unsigned char c){}
For those few exotic systems that have 16 bit bytes or other oddities like 1's complement, they cannot support uint8_t
in the first place.
0 comment threads