The correct type is uint8_t/u8. Sadly, using that to alias other types is undefined. I've also seen hashing algorithms which used uint16_t/u16, with similar aliasing optimization bugs. Sometimes you want to reinterpret things as a struct, too.
This is the reason why Linux compiles with strict aliasing disabled.
uint8_t is not guaranteed to be unsigned char but in practice almost always is. GCC did originally have separate 8 bit types when stdint.h was introduced but quickly changed to a typedef for char-based types precisely to allow using it for aliasing.
Yes, technically char may not be 8 bits but in practice that is very rare (and you can statically assert it).
Overall IMO the best solution is always use uint8_t and turn off optimisations on those rare weird platforms where it's not an alias for unsigned char for whatever reason.
Does this imply any unsigned char typedef is able to alias anything? Or is uint8_t a compiler special case?
IIRC POSIX guarantees that char is 8 bits though (but I still think that the sign is implementation-dependent).
But as I said in a parent comment, I don't understand why it's even relevant. If you want to alias any type then use `char *` and not anything else. I don't understand why one would prefer using stdint for that.
This is independent of how many bytes the underlying platform can address. If we have 8 bit processing code but the platform can only address 16 bits at a time, it should be up to the compiler to generate code that works. Compilers already do stuff like that in other circumstances.
By definition `sizeof(char) == 1`, so that's almost always what you want when messing with types in C anyway. What you want is bytes, not octets.