Quotes of the week
Posted Apr 5, 2012 11:31 UTC (Thu) by
juliank (subscriber, #45896)
Parent article:
Quotes of the week
Rob Pike is absolutely right. Swapping bytes in C code is just wrong in almost all cases (probably in all cases).
If you use clang and want the slightly faster code using byteswapping to be created, you can just wrap a n-byte char array in a union with an n-byte integer and then extract the characters as Rob described. Clang will automatically transform this into a byte swap instruction or a move instruction. This even works if you use a loop (to create more generic code).
Here's also some example code showing this:
typedef union {
uint32_t value;
unsigned char buf[4];
} uint32_le_t;
uint32_t read32le(uint32_le_t in)
{
uint32_t out = 0;
for (unsigned int i = 0; i < sizeof(in); i++)
out |= (uint32_t) in.buf[i] << (8 * i);
return out;
}
For those who like C++, a template for reading integers in a specific byte order (byte order decided by the template parameter 'little'):
template<typename T, bool little> struct jak__byte_swapping_ {
inline jak__byte_swapping_(T in) {
u.value = in;
u.value = read(u);
}
inline operator T () const {
return read(u);
}
private:
union u_type {
T value;
unsigned char buf[sizeof(T)];
} u;
static inline T read(const u_type in) {
T out = 0;
if (little) {
for (unsigned int i = 0; i < sizeof(in); i++)
out |= (T) in.buf[i] << (8 * i);
} else {
for (unsigned int i = 0; i < sizeof(in); i++)
out |= (T) in.buf[sizeof(in) - 1 - i] << (8 * i);
}
return out;
}
};
It obviously misses a constructor for dealing with the specified endianness data (currently it takes native integers), but that could be added. In it's current form, it is mostly useful to use as a struct member to describe a binary format (you read the file into the struct and then you can just treat the specified-endianness integer like a native one).
(
Log in to post comments)