Understanding Little Endian And Big Endian with Examples and Code

This article is the continuation of the Series on the C programming tutorial and carries the discussion on C language programming and its implementation. It aims to provide easy and practical examples for understanding the C program. In our last article, we have seen the Qualifiers in C programming. In this article, we are going to see Little Endian and Big Endian in C programming.

Learn about the concepts of Little Endian and Big Endian in C, two formats used to store multibyte data in a computer’s memory. This comprehensive tutorial explains endianness, provides examples to demonstrate memory arrangements, and offers code snippets to find and convert endianness. Discover the importance of endianness in different scenarios and how to make the right choice for your system.

Normally, Big Endian and Little Endian are two formats to store multibyte data types in a computer’s memory. Before that, we should know what is Endian.

What is Endianness?

The endianness refers to the byte order used by your computer or microcontroller or a machine to read or write a single “machine word” in memory (32-bit machine’s word size is 32-bit and 64-bit machine’s word size is 64-bit ). In other words, The endian will decide how to store multiple bytes in computer memory. It doesn’t mean, the order of bits inside a byte,  nor the way the computer reads an array of bytes or a file. It’s all about the order of the bytes of a word (multi-byte variable) in memory.

Now we will move into Little Endian and Big Endian.

Difference between Little Endian and Big Endian

Little Endian

In Little-endian, LSB (Least significant byte) is stored first or to a lower memory address. Intel x86, Pentium are using this Little Endian.

Thus, the little-endian byte order means, when the computer writes a word (Multi Byte) into memory, it begins by writing the Lowest byte to the lowest memory address and continues until it has written the highest byte to the highest memory address. It does this by writing subsequent and ascending memory addresses, no matter the endianness.

Big Endian

In Big Endian, MSB (Most significant byte) is stored first or to a lower memory address. Big-endian is implemented in PowerPC and most networking devices.

The big-endian byte order means, when the computer writes a word (Multi Byte) into memory, it begins by writing the highest byte to the lowest memory address and continues until it has written the lowest byte to the highest memory address.

Now we will see the example, then you will understand very easily.

Example

Consider the number 0x11223344. This number is written with hexadecimal digits (prefix “0x”). Its decimal value is 287454020. It consists of 4 bytes: 0x11, 0x22, 0x33 and 0x44.

In this value LSB is 0x44 and MSB is 0x11.

Now assume that the computer wants to write this number into memory beginning at address 100. This 4-byte value. So it will use the memory address 100, 101, 102, 103.

Big Endian

If the computer uses the Big endian byte order, it begins with the MSB (byte 0x11) and writes it at address 100. Then it writes the next byte 0x22 at address 101, the byte 0x33 at address 102, and at last the MSB (byte 0x44) at the last address 103. This results in the following memory content:

Memory Address100101102103
Content0x110x220x330x44

Little Endian

If the computer uses the Little endian byte order, it begins with the LSB (byte 0x44) and writes it at address 100 and then it goes the word backward until it writes the MSB. So it writes the next byte 0x33 at address 101, then it writes 0x22 at address 102, and at last the MSB 0x11 at address 103. Note again that the computer uses sequential ascending addresses, no matter the endianness. This result is the following memory content:

Memory Address100101102103
Content0x440x330x220x11

Program

Now we are going to write a program to see the memory arrangement on our computer. This program will print the memory address and content of our value.

endian.c

#include <stdio.h>
 
int main(void)
{
 unsigned int value = 0x11223344;
 char *r = (char *) &value;
 int i;
 
 for(i=0; i<4; i++) {
 printf("Address of 0x%x = %d \n", r[i], &r[i]);
 }
 return 0;
}

Compile the program

gcc -o endian endian.c

Run the program

./endian

Output

Address of 0x44 = 1247158856 
Address of 0x33 = 1247158857 
Address of 0x22 = 1247158858 
Address of 0x11 = 1247158859

If you see the output, 0x44 (LSB) in the Lowest Address and 0x11 (MSB) in the Highest Address. So this system is the Little Endian System.

Find the Endianness

We can find our system Endianness in many ways. Here I wrote the program in many ways.

Example 1

#include <stdio.h>
  
int main(void)
{
    unsigned int value = 0x1;
    char *r = (char *) &value;
 
    if (*r == 1) 
        printf("Your system is Little Endian\n");
    else
        printf("Your system is Big Endian\n");
    return 0;
}

Output

Your system is Little Endian

Example 2

We can find the Endianness of the system using Union. See the below program.

#include <stdio.h>

union check_endian
{
    unsigned int value;
    char r;
};


union check_endian endian;

  
int main(void)
{
    endian.value = 0x1;
 
    if (endian.r == 1) 
        printf("Your system is Little Endian\n");
    else
        printf("Your system is Big Endian\n");
    return 0;
}

Output

Your system is Little Endian

Convert One Endian to Another Endian

Again there are many ways to convert one endian to another endian. Here these programs are used to convert from given endianness to another endianness. If the given endianness is little it converts to big endian and vice versa. This code has been written keeping in mind sizeof(int) = 4 Bytes.

Example 1

#include <stdio.h>
  
int main(void)
{
    int value = 0x11223344;
    int converted = 0;
    
    printf("Value Before Converting = 0x%x\n", value);
    
    converted |= ((0xff & value) << 24);
    converted |= (((0xff << 8) & value) <<8);
    converted |= (((0xff << 16) & value) >> 8);
    converted |= (((0xff << 24) & value) >> 24);
    
    
    printf("Value After Converting = 0x%x\n", converted);
    return 0;
}

Output

Value Before Converting = 0x11223344
Value After Converting = 0x44332211

Example 2

#include <stdio.h>
 
int main(void)
{
 int value = 0x11223344;
 int converted = 0;
 
 printf("Value Before Converting = 0x%x\n", value);
 
 converted |= ((0x000000ff & value) << 24);
 converted |= ((0x0000ff00 & value) << 8);
 converted |= ((0x00ff0000 & value) >> 8);
 converted |= ((0xff000000 & value) >> 24);
 
 
 printf("Value After Converting = 0x%x\n", converted);
 return 0;
}

Output

Value Before Converting = 0x11223344
Value After Converting = 0x44332211

Example 3

Write a MACRO to convert one Endian to another Endian.

#include <stdio.h>

#define convert(value) ((0x000000ff & value) << 24) | ((0x0000ff00 & value) << 8) | \
                       ((0x00ff0000 & value) >> 8) | ((0xff000000 & value) >> 24)

int main(void)
{
int value = 0x11223344;
int converted = 0;

printf("Value Before Converting = 0x%x\n", value);

converted = convert(value);


printf("Value After Converting = 0x%x\n", converted);
return 0;
}

Output

Value Before Converting = 0x11223344
Value After Converting = 0x44332211

Importance of Endian

When you write software that runs on a single machine, usually you do not care for the endianness. When the machine is part of a network, with other machines using different architectures, and the software communicates with others in this network, a transformation must be applied before sending, or after reading data.

However, there are cases when you care for endianness even if your software runs on a single machine. Different file formats use different endianness. For instance, the JPEG format uses big-endian representation, so if you write a program that saves JPEG images and runs on a little-endian machine, you must reverse all the bytes before writing it to disk.

Normally, the endianness of a computer does not play a big role for the programmer, at least as long as the programmer is not doing any network magic in C or some wild pointer black magic. There are nevertheless cases where the lack of this knowledge can lead to scary bugs.

Suppose you are manipulating some binary data in memory, say an array of integers having some meaning. You want to set the first byte of every integer, that is the most significant one, to 0. Because you are a mighty C-wizard, you go on and cast the data array to a pointer to char and iterate over the array like this:

/* This program should set the most significant byte of
 * every integer in the array data to 0.
 * The first element should be thus set to 0x00345678 */
 
#include <stdio.h>
 
#define SIZE 8
/* some binary data */
unsigned int data[SIZE] =
{
    0x12345678, 0x9ABCDEF0, 0X11223344, 0X55667788,
    0x99AABBCC, 0xDDEEFF00, 0x11122233, 0x34445556
};
 
int main(void)
{
    /* p is start address of data */
    char *p = (char*) data;
    size_t i;
 
    for (i = 0; i < sizeof(data); i += 4) {
        *(p + i) = 0x0;
    }
 
    return 0;
}

You might think, that p is always pointing to the first (most significant) byte of every integer. You might think that you have the following situation:

0x12 0x34 0x56 0x78
p

But this is not the case on a little-endian machine. On such a machine, p is always pointing to the last byte of every integer (the least significant one) because even though p contains the start address of the first array element, the integer bytes are reversed in memory, like this:

0x78 0x56 0x34 0x12
p

And another point is there is something called the “network byte order”. This is how bytes are transferred over the network. This order is the big-endian order, the one which most people find natural. This also means that every time an Intel machine receives a word over the network, it must be instructed to reverse it in order to get its actual value.

You can also read, RTOS basic concepts, I2C basics, compilation steps, and memory layout in c, pointers in c, storage classes in c, types of pointers in c, and qualifiers in c.

Which Endian is better?

When you study about endian, you might think why not only one endian? Or why we are not following one endian as a generic?

I will tell you the answer to this question. Both formats, big and little endian have their own advantages and disadvantages. First, we will see those advantages and disadvantages. Then you will find the answer to this question.

In the “Little Endian” form, assembly language instructions for picking up a 1, 2, 4, or longer byte number proceed in exactly the same way for all formats: first, pick up the lowest order byte at offset 0. Also, because of the 1:1 relationship between address offset and byte number (offset 0 is byte 0), multiple precision math routines are correspondingly easy to write.

In the “Big Endian” form, by having the high-order byte come first, you can always test whether the number is positive or negative by looking at the byte at offset zero. You don’t have to know how long the number is, nor do you have to skip over any bytes to find the byte containing the sign information. The numbers are also stored in the order in which they are printed out, so Easier to read hex dumps.

In our next article, we will see Flow control in C programming (if, if else, else if, etc.).

You can also read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
STM32F7 Bootloader TutorialsRaspberry PI Pico Tutorials
STM32F103 Bootloader TutorialsRT-Thread RTOS Tutorials
Zephyr RTOS Tutorials - STM32Zephyr RTOS Tutorials - ESP32
AUTOSAR TutorialsUDS Protocol Tutorials
Product ReviewsSTM32 MikroC Bootloader Tutorial
VHDL Tutorials
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Table of Contents