Byte Swap Little Endian and Big Endian

I have run into the Endian (not Indian) debate on numerous occasions. I even wrote an article explaining how to detect the Endianness of your operating system earlier. Simply detecting the endianness of your system is a good starting point in understand Endianess and what it means. In some cases you may need to flip your bytes from big Endian to little Endian, this is especially relevant when dealing with network packets and network programming in C. In network programming sometimes fields in a network packet will have fields that are in little Endian when most of your network fields are in big Endian, and to verify these fields you may need to swap Endianess.

For more information regarding Endianness head to the wiki article. There are also built-in C functions that do this including ntohs, ntohl, htons, htonl, however these functions are not always transferable to another architecture (MIPS, ARM) which also differ in Endianness. Therefore, I have written a few functions to byte swap 16-bit, 32-bit and 64-bit unsigned integers, if you are dealing with signed integers simply modify the functions to be signed.

u_int16_t swap_u16(u_int16_t i) {
    u_int8_t c1, c2;
 
    c1 = i & 255;
    c2 = (i >> 8) & 255;
 
    return (c1 << 8) + c2;
}
 
u_int32_t swap_u32(u_int32_t i) {
    u_int8_t c1, c2, c3, c4;    
 
    c1 = i & 255;
    c2 = (i >> 8) & 255;
    c3 = (i >> 16) & 255;
    c4 = (i >> 24) & 255;
 
    return ((u_int32_t)c1 << 24) + ((u_int32_t)c2 << 16) + ((u_int32_t)c3 << 8) + c4;
}
 
u_int64_t swap_u64(u_int64_t i) {
    u_int8_t c1, c2, c3, c4, c5, c6, c7, c8; 
 
    c1 = i & 255;
    c2 = (i >> 8) & 255;
    c3 = (i >> 16) & 255;
    c4 = (i >> 24) & 255;
    c5 = (i >> 32) & 255;
    c6 = (i >> 40) & 255;
    c7 = (i >> 48) & 255;
    c8 = (i >> 56) & 255;
 
    return ((u_int64_t)c1 << 56) + 
            ((u_int64_t)c2 << 48) + 
            ((u_int64_t)c3 << 40) + 
            ((u_int64_t)c4 << 32) + 
            ((u_int64_t)c5 << 24) + 
            ((u_int64_t)c6 << 16) + 
            ((u_int64_t)c7 << 8) + 
            c8;
}

As you can see these functions simply use a logical & with 0xFF (or 255 in decimal) then bit shift the value to its appropriate location depending on the size of the integer. If you apply the function again it will swap the values to their initial position.

Checking Endianness of your Operating System

Sometimes when trying to debug oddities in your C programs, especially when doing cross-compilation to other architectures it is good to know when going from an x86 (Little Endian) to say an ARM processor running in Big Endian.  This is doubly useful when dealing with encryption keys or network packets.  If you have an encryption key on a desktop machine running in Little Endian, and the decryption key on a Big Endian system, you have to take into account the differing byte order.  There is a great Wikipedia article about Endianness if you would like to learn more. There is also a nifty C program you can compile to check the Endianess of your OS.

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    int x = 1;
 
    if (*(char *)&x == 1)
        fprintf(stderr, "Little Endian\n");
    else
        fprintf(stderr, "Big Endian\n");
 
    return 0;
}

To compile:

gcc -o endian endian.c

Then run:

erik@debian:~$ ./endian
Little Endian

Voila, now you know the Endianness of your Operating System.