4 ms·
> I don't think this works just because she's masking it. I'm pretty sure it's working because she cast (255 & p[0]) to uint32_t You're right, masking does not
by moefh 2y ago
> I don't think this works just because she's masking it. I'm pretty sure it's working because she cast (255 & p[0]) to uint32_t
You're right, masking does nothing to solve the problem, what does it is the cast to uint32_t. Masking only helps if you're working with (signed) char, which is a bit silly.
Your example works without the cast because the example in the article doesn't show the problem. That is, the following code doesn't have undefined behavior:
char b[4] = {0x02,0x03,0x04,0x80};
#define READ32BE(p) p[3] | p[2]<<8 | p[1]<<16 | p[0]<<24
int main(int argc, char *argv[]) { printf("%08x\n", READ32BE(b)); }
Note that b[0] (which is being shifted by 24) is 0x02, so everything works. To show the problem you'd need something like this (b[0] must be >= 128):
char b[4] = {0x82,0x03,0x04,0x80};
- trealira 2y agoThanks for the explanation! That makes sense. I knew from reading K&R that, in converting a char to an int without sign extension, casting to unsigned char first is just as good as masking by 0xFF after, and I guess I was just not sufficiently familiar with the type promotion rules of C. This now causes a runtime error: #include <stdio.h> #include <stdint.h> char b[4] = {0x82,0x03,0x04,0x80}; #define UC(x) ((unsigned char) (x)) #define READ32BE(p) (uint32_t)UC(p[3]) | UC(p[2]) << 8 | UC(p[1]) << 16 | UC(p[0]) << 24 int main(void) { printf("%08x\n", READ32BE(b)); } ---- endian.c:8:22: runtime error: left shift of 130 by 24 places cannot be represented in type 'int' 82030480 But this works: #include <stdio.h> #include <stdint.h> char b[4] = {0x82,0x03,0x04,0x80}; #define CH_to_U32(x) ((uint32_t) (unsigned char) (x)) #define READ32BE(p) (CH_to_U32(p[3]) \ | CH_to_U32(p[2]) << 8 \ | CH_to_U32(p[1]) << 16 \ | CH_to_U32(p[0]) << 24) int main(void) { printf("%08x\n", READ32BE(b)); } ---- 82030480