4

I see a way to know the endianness of the platform is this program but I don't understand it

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

What does the test do?

Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424
  • 1
    possible duplicate of [Detecting endianness programmatically in a C++ program](http://stackoverflow.com/questions/1001307/detecting-endianness-programmatically-in-a-c-program) – Donal Fellows Aug 28 '12 at 14:34
  • 2
    @DonalFellows not sure on dup, this question has found code and wants to know how it works. The potential dup is just asking the general question on how to detect endianness. – Doug T. Aug 28 '12 at 14:39
  • 1
    possible duplicate of [Little vs Big Endianess: How to interpret the test](http://stackoverflow.com/questions/9971369/little-vs-big-endianess-how-to-interpret-the-test) – Bo Persson Aug 28 '12 at 16:05
  • 1
    Also note that the result is not very reliable, because big endian and little endian are not the only options, some crazy hardware do ints and floats differently, and some CPUs can be configured at runtime. – Bo Persson Aug 28 '12 at 16:15

8 Answers8

9

An int is almost always larger than a byte and often tracks the word size of the architecture. For example, a 32-bit architecture will likely have 32-bit ints. So given typical 32 bit ints, the layout of the 4 bytes might be:

   00000000 00000000 00000000 00000001

or with the least significant byte first:

   00000001 00000000 00000000 00000000

A char* is one byte, so if we cast this address to a char* we'll get the first byte above, either

   00000000

or

   00000001

So by examining the first byte, we can determine the endianness of the architecture.

Doug T.
  • 64,223
  • 27
  • 138
  • 202
4

This would only work on platforms where sizeof(int) > 1. As an example, we'll assume it's 2, and that a char is 8 bits.

Basically, with little-endian, the number 1 as a 16-bit integer looks like this:

00000001 00000000

But with big-endian, it's:

00000000 00000001

So first the code sets a = 1, and then this:

*( (char*)&a ) == 1)

takes the address of a, treats it as a pointer to a char, and dereferences it. So:

  • If a contains a little-endian integer, you're going to get the 00000001 section, which is 1 when interpeted as a char

  • If a contains a big-endian integer, you're going to get 00000000 instead. The check for == 1 will fail, and the code will assume the platform is big-endian.

You could improve this code by using int16_t and int8_t instead of int and char. Or better yet, just check if htons(1) != 1.

James M
  • 18,506
  • 3
  • 48
  • 56
  • C89 2.2.4.2 and C99 5.2.4.2.1 require `sizeof(int) > 1`, by dint of requiring that `INT_MIN` and `INT_MAX` have values exceeding the capacity of `char`, so while your caveat is true, it's vacuously true. Somewhat more interesting is that this code would work incorrectly on middle-endian systems that aren't big-endian or small-endian. (Although the frequency of such systems is small enough that if you have to ask what they are, you probably don't have to care about them. :-) ) – Jeff Walden Feb 23 '13 at 23:00
2
  1. take the address of a
  2. cast it to char*
  3. dereference this char*, this will give you the first byte of the int
  4. check its value - if it's 1, then it's little endian. Otherwise - big.

Assume sizeof(int) == 4, then:

|........||........||........||........|    <- 4bytes, 8 bits each for the int a
| byte#1 || byte#2 || byte#3 || byte#4 |

When step 1, 2 and 3 are executed, *( (char*)&a ) will give you the first byte, | byte#1 |.

Then, by checking the value of byte#1 you can understand if it's big or little endian.

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
2
  • You can look at an integer as a array of 4 bytes (on most platforms). A little endian integer will have the values 01 00 00 00 and a big endian 00 00 00 01.
  • By doing &a you get the address of the first element of that array.
  • The expression (char*)&a casts it to the address of a single byte.
  • And finally *( (char*)&a ) gets the value contained by that address.
Bart
  • 1,633
  • 14
  • 21
1

The program just reinterprets the space taken up by an int as an array of chars and assumes that 1 as an int will be stored as a series of bytes, the lowest order of which will be a byte of value 1, the rest being 0.

So if the lowest order byte occurs first, then the platform is little endian, else its big endian.

These assumptions may not work on every single platform in existance.

quamrana
  • 37,849
  • 12
  • 53
  • 71
1
a = 00000000 00000000 00000000 00000001
    ^                                 ^
    |                                 |
    &a if big endian                  &a if little endian

    00000000                   00000001
    ^                                 ^
    |                                 |
    (char*)&a for BE                  (char*)&a for LE

    *(char*)&a = 0 for BE             *(char*)&a = 1 for LE
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
khachik
  • 28,112
  • 9
  • 59
  • 94
  • Just be aware that this nice graphic flips the sense of endianness: It moves the apparent place of where the calculated pointer points to instead of reordering the bytes of an integer. – quamrana Aug 28 '12 at 14:44
1

Here's how it breaks down:

           a        -- given the variable a
          &a        -- take its address; type of the expression is int *
  (char *)&a        -- cast the pointer expression from type int * to type char *
*((char *)&a)       -- dereference the pointer expression
*((char *)&a) == 1  -- and compare it to 1

Basically, the cast (char *)&a converts the type of the expression &a from a pointer to int to a pointer to char; when we apply the dereference operator to the result, it gives us the value stored in the first byte of a.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0
*( (char*)&a )

In BigEndian data for int i=1 (size 4 byte) will arrange in memory as:- (From lower address to higher address).

00000000 -->Address 0x100
00000000 -->Address 0x101
00000000 -->Address 0x102
00000001 -->Address 0x103

While LittleEndian is:-

00000001 -->Address 0x100
00000000 -->Address 0x101
00000000 -->Address 0x102
00000000 -->Address 0x103

Analyzing the above cast:-

Also &a= 0x100 and thus
*((char*)0x100) implies consider by taking one byte(since 4 bytes loaded for int) a time so the data at 0x100 will be refered.

*( (char*)&a ) == 1 => (*0x100 ==1) that is 1==1 and so true,implying its little endian. 
perilbrain
  • 7,961
  • 2
  • 27
  • 35