3 ms·
When I read the blog post I saw this, #define READ32BE(p) bswap_32(*(uint32_t *)(p)) Which as you correctly state in the article, is incorrect code. We ag
by klodolph 6y ago
When I read the blog post I saw this,
#define READ32BE(p) bswap_32(*(uint32_t *)(p))
Which as you correctly state in the article, is incorrect code. We agree about this. I proposed an alternate solution, where the READ32BE would be like this:
uint32_t read32be(const void *ptr) {
uint32_t x;
memcpy(&x, ptr, sizeof(x));
return swap32be(x); // Nop on big-endian.
}
What I like about this is that it breaks the problem down into two parts: reading unaligned data and converting byte order. The reason for this is, sometimes, you need a half of that. Some wire formats have alignment guarantees, and if you know that the alignment guarantees are compatible with your platform, you can just read the data into a buffer and then (optionally) swap the bytes in place.
Just to give an example... not too long ago I was working with legacy code that was written for MIPS. Unaligned access does not work on MIPS, so the code was already carefully written to avoid that. All I had to do was make sure that the data types were sized (e.g. replace "long" with "int32_t") and then go through and byte swap everything.
struct Something {
int32_t x, y;
char name[16];
};
void Something_Swap(struct Something *p) {
p->x = swap32be(p->x);
p->y = swap32be(p->y);
}
So it's nice to have a function like swap32be(), and "you don't have to mask and shift" I would say is true, it just depends on which compilers you want to support. I would say that a key part of being a C programmer is making a conscious decision about which compilers you want to support.
Yes, I'm aware that structs are not a great way to serialize data in general, but sometimes they're damn convenient.