Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics

Dashboard
Notifications
Mark all as read
Q&A

Is `uint8_t` always an alias for a character type if it exists?

+7
−0

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++);
  }
}
Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

0 comments

1 answer

+6
−0

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 here void 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.

Why does this post require moderator attention?
You might want to add some details to your flag.

6 comments

Could there be an implementation-specific type like __u8, which is a distinct type from unsigned char even though both are 8 bits? Then uint8_t could be an alias for that. Ayxan Haqverdili‭ about 1 month ago

@Ayxan Haqverdili‭ The key here is 8 bit two's complement. Some manner of custom type could in theory have all manner of representations. unsigned char can only have one representation and signed char can only be 1's compl, 2's compl or signed magnitude. In case the system uses 2's compl and 8 bit characters, then the uint8_t and int8_t will use that too. Since 2's complement must be supported and UINTN_MAX honored, there can be no trap representations. But __u8 could be anything. Lundin‭ about 1 month ago

I am assuming __u8 is an integer type exactly like unsigned char except for the strict aliasing rule. So, a function like void foo(__u8* a, int* b); can assume that the arguments are pointing to different memory addresses. Would it then be possible for an implementation to do typedef __u8 uint8_t;? I don't understand how representation of the integers (2's compl, etc.) apply here. Ayxan Haqverdili‭ about 1 month ago

@Ayxan Haqverdili‭ It doesn't make sense for a compiler to implement any other character type than unsigned char so why would it? If there exists a type unsigned char which is 8 bits and another type uint8_t which is also 8 bits and neither have padding bits, why would you make them non-compatible or different types? Simply to break your own compiler? Lundin‭ about 1 month ago

@Ludin Could be done to allow more aggressive optimizations by taking advantage of the fact that strict aliasing applies. The kind of optimization restrict allows in C. Ayxan Haqverdili‭ about 1 month ago

Show 1 more comments

Sign up to answer this question »