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 Address | 100 | 101 | 102 | 103 |
Content | 0x11 | 0x22 | 0x33 | 0x44 |
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 Address | 100 | 101 | 102 | 103 |
Content | 0x44 | 0x33 | 0x22 | 0x11 |
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.

Embedded Software | Firmware | Linux Devic Deriver | RTOS
Hi, I’m SLR. I am a tech blogger and an Embedded Engineer. I am always eager to learn and explore tech-related concepts. And also, I wanted to share my knowledge with everyone in a more straightforward way with easy practical examples. I strongly believe that learning by doing is more powerful than just learning by reading. I love to do experiments. If you want to help or support me on my journey, consider sharing my articles, or Buy me a Coffee! Thank you for reading my blog! Happy learning!