Endianness
Endianness refers to the order of the bytes, comprising a digital word, in computer memory. It also describes the order of byte transmission over a digital link. Words may be represented in big-endian or little-endian format. With big-endian the most-significant byte of a word is stored at a particular memory address and the subsequent bytes are stored in the following higher memory addresses, the least significant byte thus being stored at the highest memory address. Little-endian format reverses the order and stores the least-significant byte at the lower memory address with the most significant byte being stored at the highest memory address.[1]
Both forms of endianness are widely used in digital electronics. The choice of endianness for a new design is often arbitrary, but later technology revisions and updates perpetuate the existing endianness and many other design attributes to maintain backward compatibility. As examples, the IBM z/Architecture mainframes use big-endian while the Intel x86 processors use little-endian. The designers chose endianness in the 1960s and 1970s respectively.
Big-endian is the most common format in data networking; fields in the protocols of the Internet protocol suite, such as IPv4, IPv6, TCP, and UDP, are transmitted in big-endian order. For this reason, big-endian byte order is also referred to as network byte order. Little-endian storage is popular for microprocessors, in part due to significant influence on microprocessor designs by Intel Corporation. Mixed forms also exist, for instance the ordering of bytes in a 16-bit word may differ from the ordering of 16-bit words within a 32-bit word. Such cases are sometimes referred to as mixed-endian or middle-endian. There are also some bi-endian processors that operate in either little-endian or big-endian mode.
Contents
Illustration
Endianness may be demonstrated by writing a decimal number on paper in the conventional way which uses positional notation. The digits are written left to right, with the most significant digit to the left, which is analogous to the lowest address of memory used to store a number.
For example, the number 123, has the hundreds-digit, 1, left-most which is understood by a numerate reader. This is an example of a big-endian convention taken from daily life. The little-endian way of writing the same number would place the digit 1 in the right-most position: 321. A person following conventional place-value order, who is not aware of this special ordering, would read the number as three hundred and twenty one. Endianness in computing is similar, but it applies to the ordering of bytes in memory or during transmission.
The illustrations to the right, where a is a memory address, show big-endian and little-endian storage in memory.
History
Before microprocessors, most computers used big-endian, but the PDP-11 was a notable exception. The Datapoint 2200 used simple bit-serial logic with little-endian to facilitate carry propagation. When Intel developed the 8008 microprocessor for Datapoint, they used little-endian for compatibility. However, as Intel was unable to deliver the 8008 in time, Datapoint used a medium scale integration (MSI) equivalent.[2][3]
Dealing with data of different endianness is sometimes termed the NUXI problem.[4] This terminology alludes to the byte order conflicts encountered while adapting UNIX, which ran on the little-endian PDP-11, to a big-endian computer such as the IBM Series/1. One of the first programs converted was supposed to print out Unix, but on the Series/1 it printed nUxi instead.[5] Unix was one of the first systems to allow the same code to run on, and transfer data between, platforms with different internal representations.
Etymology
Danny Cohen introduced use of the terms Little-Endian and Big-Endian for byte ordering in a well-known document in 1980.[6][7] In this technical and political examination of byte ordering issues, the "endian" names were pointedly drawn from Jonathan Swift's 1726 satirical fantasy novel, Gulliver’s Travels, in which civil war erupts over whether the big or the small end of a soft-boiled egg is the proper end to crack open.[8][9]
Hardware
Computer memory consists of a sequence of storage cells. Each cell is identified in hardware and software by its memory address. If the total number of storage cells in memory is n, then addresses are enumerated from 0 to n-1. Computer programs often use data structures of fields that may consist of more data than is stored in one memory cell. For the purpose of this article where its use as an operand of an instruction is relevant, a field consists of a consecutive sequence of bytes and represents a simple data value. In addition to that, it has to be of numeric type in some positional number system (mostly base-10 or base-2 — or base-256 in case of 8-bit bytes).[10] In such a number system the "value" of a digit is determined not only by its value as a single digit, but also by the position it holds in the complete number, its "significance". These positions can be mapped to memory mainly in two ways:[11]
- increasing numeric significance with increasing memory addresses (or increasing time), known as little-endian, and
- decreasing numeric significance with increasing memory addresses (or increasing time), known as big-endian[12]
The Intel x86 and x86-64 series of processors use the little-endian format, and for this reason, it is also known in the industry as the "Intel convention".[13][14] Other well-known little-endian processor architectures are the 6502 (including 65802, 65C816), Z80 (including Z180, eZ80 etc.), MCS-48, DEC Alpha, Altera Nios II, Atmel AVR, VAX, and, largely, PDP-11. The Intel 8051, contrary to other Intel processors, expects 16-bit addresses in big-endian format, except for the LCALL instruction whose target address is stored in little-endian format.[15]
The Motorola 6800 and 68k series of processors use the big-endian format, and for this reason, it is also known as the "Motorola convention".[13][14] Other well-known processors that use the big-endian format include the Xilinx Microblaze, SuperH, IBM POWER, Atmel AVR32, and System/360 and its successors such as System/370, ESA/390, and z/Architecture. The PDP-10 also used big-endian addressing for byte-oriented instructions.
SPARC historically used big-endian until version 9, which is bi-endian, similarly the ARM architecture was little-endian before version 3 when it became bi-endian, and the PowerPC and Power Architecture descendants of POWER are also bi-endian.
Bi-endian hardware
Some architectures (including ARM versions 3 and above, PowerPC, Alpha, SPARC V9, MIPS, PA-RISC, SuperH SH-4 and IA-64) feature a setting which allows for switchable endianness in data segments, code segments or both. This feature can improve performance or simplify the logic of networking devices and software. The word bi-endian, when said of hardware, denotes the capability of the machine to compute or pass data in either endian format.
Many of these architectures can be switched via software to default to a specific endian format (usually done when the computer starts up); however, on some systems the default endianness is selected by hardware on the motherboard and cannot be changed via software (e.g. the Alpha, which runs only in big-endian mode on the Cray T3E).
Note that the term "bi-endian" refers primarily to how a processor treats data accesses. Instruction accesses (fetches of instruction words) on a given processor may still assume a fixed endianness, even if data accesses are fully bi-endian, though this is not always the case, such as on Intel's IA-64-based Itanium CPU, which allows both.
Note, too, that some nominally bi-endian CPUs require motherboard help to fully switch endianness. For instance, the 32-bit desktop-oriented PowerPC processors in little-endian mode act as little-endian from the point of view of the executing programs, but they require the motherboard to perform a 64-bit swap across all 8 byte lanes to ensure that the little-endian view of things will apply to I/O devices. In the absence of this unusual motherboard hardware, device driver software must write to different addresses to undo the incomplete transformation and also must perform a normal byte swap.
Some CPUs, such as many PowerPC processors intended for embedded use, allow per-page choice of endianness.
Floating-point
Although the ubiquitous x86 processors of today use little-endian storage for all types of data (integer, floating point, BCD), there have been a few historical machines where floating point numbers were represented in big-endian form while integers were represented in little-endian form.[16] There are old ARM processors that have half little-endian, half big-endian floating point representation for double-precision numbers: both 32-bit words are stored in little-endian like integer registers, but the most significant one first. Because there have been many floating point formats with no "network" standard representation for them, there is no formal standard for transferring floating point values between diverse systems. It may therefore appear strange that the widespread IEEE 754 floating point standard does not specify endianness.[17] Theoretically, this means that even standard IEEE floating point data written by one machine might not be readable by another. However, on modern standard computers (i.e., implementing IEEE 754), one may in practice safely assume that the endianness is the same for floating point numbers as for integers, making the conversion straightforward regardless of data type. (Small embedded systems using special floating point formats may be another matter however.)
Optimization
The little-endian system has the property that the same value can be read from memory at different lengths without using different addresses (even when alignment restrictions are imposed). For example, a 32-bit memory location with content 4A 00 00 00 can be read at the same address as either 8-bit (value = 4A), 16-bit (004A), 24-bit (00004A), or 32-bit (0000004A), all of which retain the same numeric value. Although this little-endian property is rarely used directly by high-level programmers, it is often employed by code optimizers as well as by assembly language programmers.
On the other hand, in some situations it may be useful to obtain an approximation of a multi-byte or multi-word value by reading only its most-significant portion instead of the complete representation; a big-endian processor may read such an approximation using the same base-address that would be used for the full value.
Calculation order
Little-endian representation simplifies hardware in processors that add multi-byte integral values a byte at a time, such as small-scale byte-addressable processors and microcontrollers. As carry propagation must start at the least significant bit (and thus byte), multi-byte addition can then be carried out with a monotonically-incrementing address sequence, a simple operation already present in hardware. On a big-endian processor, its addressing unit has to be told how big the addition is going to be so that it can hop forward to the least significant byte, then count back down towards the most significant. However, high-performance processors usually perform these operations simultaneously, fetching multi-byte operands from memory as a single operation, so that the complexity of the hardware is not affected by the byte ordering. Also, since division is done starting from the MSB, this advantage is just about gone on larger machines.
Mapping multi-byte binary values to memory
Big-Endian | Little-Endian | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
C-type | name | initial value | memory at offset | memory at offset | |||||||||
of variable | +0 | +1 | +2 | +3 | +0 | +1 | +2 | +3 | |||||
int32_t |
longVar | = 168496141; | 0Ah | 0Bh | 0Ch | 0Dh | 0Dh | 0Ch | 0Bh | 0Ah | |||
int16_t |
shortVar | = 3085; | 0Ch | 0Dh | 0Dh | 0Ch | |||||||
A simple way to remember is "In Little Endian, the Least significant byte goes into the Lowest-addressed slot". So in the example in the table, 0Dh, the least significant byte, in a Little-Endian system goes into slot +0. |
Let us agree to understand the orientation left to right in memory as increasing memory addresses − as in the table to the left. Furthermore, the hex value 0x0a0b0c0d is defined to be the value 168496141 in the usual (and big-endian style) decimal notation. If you map this value as a binary value to a sequence of 4 bytes in memory in big-endian style, you are writing the bytes from left to right in decreasing significance: 0Ah at +0, 0Bh at +1, 0Ch at +2, 0Dh at +3. However, on a little-endian system, the bytes are written from left to right in increasing significance, starting with the one's byte: 0Dh at +0, 0Ch at +1, 0Bh at +2, 0Ah at +3. If you write a 32-bit binary value to a memory location on a little-endian system and after that output the memory location (with growing addresses from left to right), then the output of the memory is reversed (byte-swapped) compared to usual big-endian notation. This is the way a hexdump is displayed: because the dumping program is unable to know what kind of data it is dumping, the only orientation it can observe is monotonically increasing addresses. The human reader, however, who knows that she is reading a hexdump of a little-endian system and who knows what kind of data she is reading, reads the byte sequence 0Dh,0Ch,0Bh,0Ah as the 32-bit binary value 168496141, or 0x0a0b0c0d in hexadecimal notation. (Of course, this is not the same as the number 0D0C0B0Ah = 0x0d0c0b0a = 218893066.)
Examples
This section provides example layouts of the 32-bit number 0A0B0C0Dh in the most common variants of endianness. There exist several digital processors that use other formats. That is true for typical embedded systems as well as for general computer CPUs. Most processors used in non CPU roles in typical computers (in storage units, peripherals etc.) also use one of these two basic formats, although not always 32-bit.
The examples refer to the storage in memory of the value. It uses hexadecimal notation.
Big-endian
Atomic element size 8-bit
- address increment 1-byte (octet)
increasing addresses → | |||||
0Ah | 0Bh | 0Ch | 0Dh |
The most significant byte (MSB) value, 0Ah, is at the lowest address. The other bytes follow in decreasing order of significance. This is akin to left-to-right reading in hexadecimal order.
Atomic element size 16-bit
increasing addresses → | |||||
0A0Bh | 0C0Dh |
The most significant atomic element stores now the value 0A0Bh, followed by 0C0Dh.
Little-endian
Atomic element size 8-bit
- address increment 1-byte (octet)
increasing addresses → | |||||
0Dh | 0Ch | 0Bh | 0Ah |
The least significant byte (LSB) value, 0Dh, is at the lowest address. The other bytes follow in increasing order of significance. This is akin to right-to-left reading in hexadecimal order.
Atomic element size 16-bit
increasing addresses → | |||||
0C0Dh | 0A0Bh |
The least significant 16-bit unit stores the value 0C0Dh, immediately followed by 0A0Bh. Note that 0C0Dh and 0A0Bh represent integers, not bit layouts.
When organized by byte addresses
- Byte addresses increasing from right to left
Visualising memory addresses from left to right makes little-endian values appear backwards. If the addresses are written increasing towards the left instead, each individual little-endian value will appear forwards. However strings of values or characters appear reversed instead.
With 8-bit atomic elements:
← increasing addresses | |||||
0Ah | 0Bh | 0Ch | 0Dh |
The least significant byte (LSB) value, 0Dh, is at the lowest address. The other bytes follow in increasing order of significance.
With 16-bit atomic elements:
← increasing addresses | |||||
0A0Bh | 0C0Dh |
The least significant 16-bit unit stores the value 0C0Dh, immediately followed by 0A0Bh.
The display of text is reversed from the normal display of languages such as English that read from left to right. For example, the word "XRAY" displayed in this manner, with each character stored in an 8-bit atomic element:
← increasing addresses | |||||
"Y" | "A" | "R" | "X" |
If pairs of characters are stored in 16-bit atomic elements (using 8 bits per character), it could look even stranger:
← increasing addresses | |||
"AY" | "XR" |
This conflict between the memory arrangements of binary data and text is intrinsic to the nature of the little-endian convention, but is a conflict only for languages written left-to-right, such as English. For right-to-left languages such as Arabic and Hebrew, there is no conflict of text with binary, and the preferred display in both cases would be with addresses increasing to the left. (On the other hand, right-to-left languages have a complementary intrinsic conflict in the big-endian system.)
Middle-endian
Numerous other orderings, generically called middle-endian or mixed-endian, are possible. On the PDP-11 (16-bit little-endian) for example, the compiler stored 32-bit values with the 16-bit halves swapped from the expected little-endian order. This ordering is known as PDP-endian.
- storage of a 32-bit word (hexadecimal 0A0B0C0D) on a PDP-11
increasing addresses → | |||||
0Bh | 0Ah | 0Dh | 0Ch |
The ARM architecture can also produce this format when writing a 32-bit word to an address 2 bytes from a 32-bit word alignment.
Segment descriptors on Intel 80386 and compatible processors keep a base 32-bit address of the segment stored in little-endian order, but in four nonconsecutive bytes, at relative positions 2, 3, 4 and 7 of the descriptor start.
An example of middle-endianness in everyday life is the American date format.
Networking
Many IETF RFCs use the term network order, meaning the order of transmission for bits and bytes over the wire in network protocols. Among others, the historic RFC 1700 (also known as Internet standard STD 2) has defined the network order for protocols in the Internet protocol suite to be big-endian, hence the use of the term "network byte order" for big-endian byte order; however, not all protocols use big-endian byte order as the network order.[18]
The Berkeley sockets API defines a set of functions to convert 16-bit and 32-bit integers to and from network byte order: the htons (host-to-network-short) and htonl (host-to-network-long) functions convert 16-bit and 32-bit values respectively from machine (host) to network order; the ntohs and ntohl functions convert from network to host order. These functions may be a no-op on a big-endian system.
The telephone network has always sent the most significant part first, the area code.[19]
In CANopen, multi-byte parameters are always sent least significant byte first (little endian). The same is true for Ethernet Powerlink.[20]
While the lowest network protocols may deal with sub-byte formatting, all the layers above them usually consider the byte (mostly meant as octet) as their atomic unit.
Files and byte swap
Endianness is a problem when a binary file created on a computer is read on another computer with different endianness. Some compilers have built-in facilities to deal with data written in other formats. For example, the Intel Fortran compiler supports the non-standard CONVERT
specifier, so a file can be opened as
OPEN(unit,CONVERT='BIG_ENDIAN',...)
or
OPEN(unit,CONVERT='LITTLE_ENDIAN',...)
Some compilers have options to generate code that globally enables the conversion for all file IO operations. This allows programmers to reuse code on a system with the opposite endianness without having to modify the code itself. If the compiler does not support such conversion, the programmer needs to swap the bytes via ad hoc code.
Fortran sequential unformatted files created with one endianness usually cannot be read on a system using the other endianness because Fortran usually implements a record (defined as the data written by a single Fortran statement) as data preceded and succeeded by count fields, which are integers equal to the number of bytes in the data. An attempt to read such file on a system of the other endianness then results in a run-time error, because the count fields are incorrect. This problem can be avoided by writing out sequential binary files as opposed to sequential unformatted.
Unicode text can optionally start with a byte order mark (BOM) to signal the endianness of the file or stream. Its code point is U+FEFF. In UTF-32 for example, a big-endian file should start with 00 00 FE FF
; a little-endian should start with FF FE 00 00
.
Application binary data formats, such as for example MATLAB .mat files, or the .BIL data format, used in topography, are usually endianness-independent. This is achieved by:
- storing the data always in one fixed endianness, or
- carrying with the data a switch to indicate which endianness the data was written with.
When reading the file, the application converts the endianness, invisibly from the user. An example of the first case is the binary XLS file format that is portable between Windows and Mac systems and always little endian, leaving the Mac application to swap the bytes on load and save.[21]
TIFF image files are an example of the second strategy, whose header instructs the application about endianness of their internal binary integers. If a file starts with the signature "MM
" it means that integers are represented as big-endian, while "II
" means little-endian. Those signatures need a single 16-bit word each, and they are palindromes (that is, they read the same forwards and backwards), so they are endianness independent. "I
" stands for Intel and "M
" stands for Motorola, the respective CPU providers of the IBM PC compatibles (Intel) and Apple Macintosh platforms (Motorola) in the 1980s. Intel CPUs are little-endian, while Motorola 680x0 CPUs are big-endian. This explicit signature allows a TIFF reader program to swap bytes if necessary when a given file was generated by a TIFF writer program running on a computer with a different endianness.
Note that since the required byte swap depends on the size of the numbers stored in the file (two 2-byte integers require a different swap than one 4-byte integer), the file format must be known to perform endianness conversion.
/* C function to change endianness for byte swap in an unsigned 32-bit integer */
uint32_t ChangeEndianness(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;
}
Bit endianness
Bit numbering is a similar concept to endianness in bit-level systems. Bit or bit-level endianness refers to the transmission order of bits over a serial medium. Usually that order is transparently managed by the hardware and is the bit-level analogue of little-endian (low-bit first), as in RS-232, Ethernet, and USB. Some protocols use the opposite ordering (e.g. Teletext, I²C, and SONET and SDH[22]). As bit ordering is usually only relevant on a very low level, terms like LSB first and MSB first are more descriptive for bit order than the concept of endianness.
The terms bit endianness and bit-level endianness are seldom used when talking about the representation of a stored value, as they are only meaningful for the rare computer architectures where each individual bit has a unique address. Even for systems without bit addressing, the processor documentation often needs to number the bits. Again, you find systems with both conventions.
References
- ↑ University of Maryland - Definitions. Accessed 26 Sept 2014
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Danny Cohen (1980-04-01). On Holy Wars and a Plea for Peace. IETF. IEN 137. http://www.ietf.org/rfc/ien/ien137.txt. "…which bit should travel first, the bit from the little end of the word, or the bit from the big end of the word? The followers of the former approach are called the Little-Endians, and the followers of the latter are called the Big-Endians." Also published at IEEE Computer, October 1981 issue.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ When character (text) strings are compared with one another, this is done lexicographically where a single positional element (character) also has a positional value. Lexicographical comparison means almost everywhere: first character ranks highest — as in the telephone book. This would have the consequence that almost every machine would be big-endian or at least mixed-endian. Therefore, for the criterion below to apply, the data type in question has to be numeric.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Note that, in these expressions, the term "end" is meant as "extremity", not as "last part"; and that (the extremity with) big resp. little significance is written first.
- ↑ 13.0 13.1 Lua error in package.lua at line 80: module 'strict' not found.
- ↑ 14.0 14.1 Lua error in package.lua at line 80: module 'strict' not found.
- ↑ http://www.keil.com/support/man/docs/c51/c51_xe.htm
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Reynolds, J.; Postel, J. (October 1994). "Data Notations". Assigned Numbers. IETF. p. 3. STD 2. RFC 1700. https://tools.ietf.org/html/rfc1700#page-3. Retrieved 2012-03-02.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Ethernet POWERLINK Standardisation Group (2012), EPSG Working Draft Proposal 301: Ethernet POWERLINK Communication Profile Specification Version 1.1.4, chapter 6.1.1.
- ↑ Lua error in package.lua at line 80: module 'strict' not found.
- ↑ Cf. Sec. 2.1 Bit Transmission of http://tools.ietf.org/html/draft-ietf-pppext-sonet-as-00
Further reading
- Danny Cohen (1980-04-01). On Holy Wars and a Plea for Peace. IETF. IEN 137. http://www.ietf.org/rfc/ien/ien137.txt. Also published at IEEE Computer, October 1981 issue.
- Lua error in package.lua at line 80: module 'strict' not found.
- Lua error in package.lua at line 80: module 'strict' not found.
External links
- Understanding big and little endian byte order
- Byte Ordering PPC
- Writing endian-independent code in C
This article is based on material taken from the Free On-line Dictionary of Computing prior to 1 November 2008 and incorporated under the "relicensing" terms of the GFDL, version 1.3 or later.