10.12.2009

Endianness in C

I ran into the problem of endianness when I was first starting out my most recent project to directly synthesize .au sound files. I thought I'd share some of the things I found out.

First off, endianness is the order that computers store octets in memory. A value of 1 on a big-endian machine would look like this as a 32-bit integer in hex: 00 00 00 01, whereas it would be flipped on a little-endian machine: 01 00 00 00. The least significant byte (LSB) is stored at the lowest address on little-endian machines. Keeping this fact in mind, it's easy to determine if a machine is little-endian or big-endian:

unsigned int unity = 1;
#define is_littleEndian() (*(unsigned char *)&unity)
// will return 1 if little endian, otherwise 0

Just making a char out of the first octet in the unsigned integer. If it's little-endian, the 01 will be in the least address, returning 1.

Now that you've determined whether the machine's endianness, let's review some ways you can convert from one to the other. Ints are simple enough:

int32_t endianSwap(int32_t a)
{
return a << 24 & 0xFF000000 | a << 8 & 0x00FF0000 |
a >> 8 & 0x0000FF00 | a >> 24 & 0x000000FF;
}

This works with both signed and unsigned integers. You may be asking yourself why I included the bitwise OR operations with the left and right shifts by 24. Well, right shifting signed integers is not implementation defined. The vacated bits may be filled with 1s or 0s. This is simply a precaution.

Converting floating point numbers is a little more involved, and you can't exactly convert to another double (you can, but it just makes more sense not to convert back). This is handy if you're writing data to a file.

uint64_t bigEndian_double(double a)
{
uint64_t b;
unsigned char *src = (unsigned char *)&a,
*dst = (unsigned char *)&b;

if (is_littleEndian())
{
dst[0] = src[7];
dst[1] = src[6];
dst[2] = src[5];
dst[3] = src[4];
dst[4] = src[3];
dst[5] = src[2];
dst[6] = src[1];
dst[7] = src[0];
}
else
b = *(uint64_t *)&a;

return b;
}

Comments are welcome.

2 comments:

  1. Funny, I'm googling endianness in C now because I'd also like to program au sound files. Thanks for getting ahead of me and blogging your progress. :)

    ReplyDelete
  2. Hey Andrew. If you have any questions about the .au format or need any coding help you can find me on the http://cboard.cprogramming.com/c-programming forum or you can email me. I'm going to post my code on this site soon, so stay tuned.

    ReplyDelete