> So the solution is simple right? Let's just use unsigned char instead. Sadly no. Because unsigned char in C expressions gets type promoted to the signed type int.
If you do use unsigned char, an alternative to masking would be performing the cast to uint32_t before instead of after the shift.
edit: For reference, this is what it would look like when implemented as a function instead of a macro:
static inline uint32_t read32be(const uint8_t *p)
{
return (uint32_t)p[0] << 24
| (uint32_t)p[1] << 16
| (uint32_t)p[2] << 8
| (uint32_t)p[3];
}