Endianness
Category | System |
---|
Overview
Endianness is the sequential order in which bytes are arranged when stored in memory.
Bytes are represented in big-endian or little-endian format.
Bit Endianness
Bit endianness is the convention used to identify the bit positions in a binary number.
Least Significant Byte
The least significant byte (LSB) is the byte containing the least significant bit.
![](Endianness/Untitled.png)
Most Significant Byte
The most significant byte (MSB) is the byte containing the most significant bit.
![](Endianness/Untitled 1.png)
Byte Endianness
Big-endian
Bytes are ordered from the most significant bit to the least significant bit.
The most significant bit is stored first and the least significant bit is stored last.
![](Endianness/Untitled 2.png)
Little-endian
Bytes are ordered from the least significant bit to the most significant bit.
The least significant bit is stored first and the most significant bit is stored last.
![](Endianness/Untitled 3.png)
Bi-endianness
Some architectures feature a setting which allows for switchable endianness.
Hardware
Name | Endianness |
---|---|
ARM | bi-endian |
Intel x86 | little-endian |
Intel x86-64 | little-endian |
iOS | little-endian |
PlayStation 3 | big-endian |
PlayStation 4 | little-endian |
PlayStation 5 | little-endian |
Switch | little-endian |
Wii | big-endian |
Wii U | big-endian |
Xbox 360 | big-endian |
Xbox One | little-endian |
Xbox Scarlett | little-endian |
Byte Swap
When a binary file created on a platform is read on another platform with a different endianness, byte swapping is required.
Byte swap depends on the size of the numbers (ie. a 16-bit value and a 32-bit value require a different byte swap).
The data format must therefore be known to perform endianness conversion.
Implementations
16-bit integer: swap 2 bytes.
uint16_t Swap(uint16_t value)
{
uint16_t result = 0;
result |= (value & 0x00FF) << 8;
result |= (value & 0xFF00) >> 8;
return result;
}
32-bit integer: swap 4 bytes.
uint32_t Swap(uint32_t value)
{
uint32_t result = 0;
result |= (value & 0x000000FF) << 24;
result |= (value & 0x0000FF00) << 8;
result |= (value & 0x00FF0000) >> 8;
result |= (value & 0xFF000000) >> 24;
return result;
}
32-bit floating point:
- Perform a
reinterpret_cast
from the floating point value to a 32-bit integer. Swap the integer value and performed anotherreinterpret_cast
to cast the result back to a floating point value.
reinterpret_cast
between floating point and integers values.float Swap(float value)
{
uint32_t result = Swap(reinterpret_cast<uint32_t>(value));
return reinterpret_cast<float>(result);
}
- Store the floating point value to a temporary union of a float and 32-bit integer and swap the integer value.
float Swap(float value)
{
union
{
float f;
uint32_t u;
} swap;
swap.f = x;
swap.u = Swap(swapper.u);
return swap.f;
}
Strategies
There are two strategies when generating binary data.
- Byte swap when building the data for each target platform in the expected endianness.
- Byte swap when loading the data if the endianness of the data is different from the endianness of current platform.
References
- Endianness, Wikipedia, https://en.wikipedia.org/wiki/Endianness
- Bit numbering, Wikiepdia, https://en.wikipedia.org/wiki/Bit_numbering