Endianness

Description

Endianness refers to the order in which bytes are arranged in computer memory for representing data. It decides how sequence of bytes are interpreted as data types.

There are two types:

  • Big-endian - Most significant byte is stored at smallest memory address
  • Little-endian - Least significant byte is stored at smallest memory address

For example, the 32-bit integer 0x12345678 would be stored in memory as:

Big-endian: 0x12 0x34 0x56 0x78 Little-endian: 0x78 0x56 0x34 0x12

Endianness affects how code accesses and interprets data in memory, so must be handled properly.

Solution

Byte swap code to convert between big-endian and little-endian:

Java

1
2
3
4
5
6
7
int bigToLittleEndian(int n) {
  return Integer.reverseBytes(n);
}

int littleToBigEndian(int n) {
  return Integer.reverseBytes(n);
}

C++

1
2
3
4
5
6
7
int bigToLittleEndian(int n) {
  return __builtin_bswap32(n); 
}

int littleToBigEndian(int n) {
  return __builtin_bswap32(n);
}

Python

1
2
3
4
5
6
7
import struct

def big_to_little_endian(n):
  return struct.unpack("<I", struct.pack(">I", n))[0]
  
def little_to_big_endian(n):
  return struct.unpack(">I", struct.pack("<I", n))[0] 

Built-in functions reverse byte order. Endianness must be handled properly.

Description: Endianness

Endianness refers to the byte order used to store multi-byte data types like integers and floats in memory. There are two primary types of endianness: Big-Endian and Little-Endian. In Big-Endian, the most significant byte is stored at the smallest memory address. In Little-Endian, the least significant byte is stored at the smallest memory address. Understanding endianness is crucial for tasks like networking, binary file handling, or inter-process communication where byte-level manipulation is essential.

Solution:

Detecting the system’s endianness can be done by using a union data structure, bitwise operations, or even by direct memory inspection.

Java

Java is platform-independent and always uses Big-Endian for its network byte order. However, you can manually convert between endiannesses using ByteBuffer:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class EndiannessExample {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.order(ByteOrder.BIG_ENDIAN);
        buffer.putInt(1);
        
        buffer.flip();
        
        if (buffer.get() == 1) {
            System.out.println("Big-Endian");
        } else {
            System.out.println("Little-Endian");
        }
    }
}

C++

In C++, you can use a union to detect endianness:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <iostream>

union EndianCheck {
    int integer;
    char byte;
};

int main() {
    EndianCheck ec;
    ec.integer = 1;
    if (ec.byte == 1) {
        std::cout << "Little-Endian" << std::endl;
    } else {
        std::cout << "Big-Endian" << std::endl;
    }
    return 0;
}

Python

Python’s sys library has a built-in function to check endianness:

1
2
3
4
5
6
import sys

if sys.byteorder == 'little':
    print("Little-Endian")
else:
    print("Big-Endian")

Alternatively, you can also use the struct library for manual conversion:

1
2
3
4
5
6
7
8
import struct

integer = 1
bytes_representation = struct.pack('I', integer)
if bytes_representation[0] == 1:
    print("Little-Endian")
else:
    print("Big-Endian")

Key Takeaways:

  • Endianness is about the order in which bytes are stored for multi-byte data types.
  • Java is strictly Big-Endian for network operations, but you can change it manually.
  • C++ allows you to use union for checking endianness.
  • Python provides a built-in way to check endianness with the sys library.
  • Knowing the endianness is critical in networking, file operations, and byte-level manipulation tasks.

Understanding endianness is important for low-level programming, data serialization, and communication between different systems.