5 ms·
But that code isn't portable for a different endian machine. To write portable endian clean code, you want to write functions/macros named like: cpu_to_le32
by smcameron 6y ago
But that code isn't portable for a different endian machine. To write portable endian clean code, you want to write functions/macros named like:
cpu_to_le32(),
cpu_to_be32(),
be32_to_cpu(),
le32_to_cpu(),
etc. (and similar for 16, and 64 bit quantities) similar to what's described here: https://kernelnewbies.org/EndianIssues https://kernelnewbies.org/EndianIssues)
These functions will either swap, or not, depending on the endianness of the target machine, and this decision is made at compile time, so the "no swap" case imposes no performance penalty.)
That way, the intent is clear, and the code works on big endian and little endian. So instead of what you propose, which I imagine you might use via:
x = some_value; /* say this is big endian, and we want it little endian, because we're on Intel. */
uint32_t y = read_int((char *) &x);
you'd have:
y = be32_to_cpu(x);
Now the intent is clear, and the code is portable, x is big endian, and we want native CPU (whether that be big endian or little endian).
Likewise, you could write:
x = cpu_to_be32(y);
say before writing it out to disk or network for some purpose that requires big endian.
This is similar to htonl(), ntoh(), htons(), ntohs(). (host to network/network to host long/short).
- garaetjjte 6y ago>But that code isn't portable for a different endian machine. But it is. That's the whole point, to not bother with weird endian conversion macros.
- smcameron 6y agoIt isn't. It always swaps. Most times you're dealing with endianness, you want to convert to or from native CPU to or from big or little endian. Code that always swaps regardless of native endianness will silently do the wrong thing if compiled on a machine of different endianness. You're telling me that what the linux kernel guys do is "weird endian conversion macros?" I don't believe you.
- messe 6y agoYou are wrong. It doesn't always swap. Look at the assembly I posted above comparing mips64le to mips64be. The code takes the byte at b[n] and shifts it (8.n)-bits. These are the same bytes on both little endian and big endian machines. They read the bytes in the same order (little endian), and convert them to the native order. You can also see very clearly that it doesn't always swap by looking at the simple x86_64 assembly output that the was posted where no shifts or swaps are performed. Just a mov instruction. Read the assembly. Or better yet, try the code out for yourself.
- askee 6y agoIt's also about performance. The snippet assumes the byte order of the buffer or byte stream is little endian so only covers two of four cases. If you want to read a little-endian byte stream on a big-endian machine, of course you need swapping. But, considering portability, if that byte stream had been written by the big-endian machine before (or came directly from network) it would be in big-endian ordering and swapping would be wrong. Assuming LE ordering on the writer side, you would need to swap again on a BE machine. Usually, however, you want to store in your target byte order, though. One could argue this is irrelevant as long as the memory doesn't leave your application, of course. Yet, by explicitly having macros _to_cpu, _to_be, _to_le and so on you make all of this explicit.
- sgerenser 6y agoThe snippet assumes the data being read is little endian, yes. You can make a different snippet if you want to read big endian. You use an equivalent snippet for the writing side, and boom. You never need any #ifdefs in those functions. Is it actually better than using functions like you describe? Maybe. A part of me does love the elegance of using the exact same code on any platform regardless of the native byte order. This construct was suggested/encouraged by Rob Pike: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html https://commandcenter.blogspot.com/2012/04/byte-order-fallac...
- smcameron 6y agoAh, ok. Clearly I'm not awake yet.
- messe 6y ago> But that code isn't portable for a different endian machine. Except it is. On x86, which is little endian, compilers are smart enough to convert it to a mov. > These functions will either swap, or not, depending on the endianness of the target machine So will the above. Here's the MIPS little endian version: read_int32(unsigned char*): lwl $2,3($4) j $31 lwr $2,0($4) This doesn't swap. The MIPS big endian version: read_int32(unsigned char*): lbu $3,1($4) lbu $2,2($4) sll $5,$3,8 lbu $6,0($4) sll $3,$2,16 lbu $2,3($4) or $3,$5,$3 or $3,$3,$6 sll $2,$2,24 j $31 or $2,$3,$2 This swaps and ors. What part of this do you not consider portable between different-endian machines?