87

Possible Duplicate:
C Macro definition to determine big endian or little endian machine?

int main()
{
  int x = 1;

  char *y = (char*)&x;

  printf("%c\n",*y+48);
}

If it's little endian it will print 1. If it's big endian it will print 0. Is that correct? Or will setting a char* to int x always point to the least significant bit, regardless of endianness?

Community
  • 1
  • 1
ordinary
  • 5,943
  • 14
  • 43
  • 60
  • 1
    See [this answer](http://stackoverflow.com/q/2100331/335858), it may be related. – Sergey Kalinichenko Oct 09 '12 at 01:59
  • 1
    @ordinary - Just a note that big endian and little endian are not the only options, that not all data types need to have the same [endianness](http://en.wikipedia.org/wiki/Endianness), and that some hardware can be configured at runtime. If you really need to check this, you might have to check more things. – Bo Persson Oct 09 '12 at 07:55
  • If you have the option, consider bitwise operations on fixed width datatypes to extract/set bits. They are portable [according to this answer](http://stackoverflow.com/a/12730780/3041008) – mucaho Jul 30 '15 at 03:33
  • Great endianness demo code for userland and even a kernel module: https://gitlab.com/eric.saintetienne/endianness – Eric Apr 15 '20 at 11:10
  • 1
    Why use ASCII. Use `'0'`. Why print as a char and not an int. Why start as an int. – young_souvlaki Jul 07 '20 at 13:52
  • 1
    To answer part of my question, print as `char` so C only reads a byte of data. Start as `int` so that we have multiple bytes and can inspect endianness. Cast to `char` now seems unnecessary, just print as `char`. – young_souvlaki Jul 07 '20 at 14:32

4 Answers4

140

In short, yes.

Suppose we are on a 32-bit machine.

If it is little endian, the x in the memory will be something like:

       higher memory
          ----->
    +----+----+----+----+
    |0x01|0x00|0x00|0x00|
    +----+----+----+----+
    A
    |
   &x

so (char*)(&x) == 1, and *y+48 == '1'. (48 is the ascii code of '0')

If it is big endian, it will be:

    +----+----+----+----+
    |0x00|0x00|0x00|0x01|
    +----+----+----+----+
    A
    |
   &x

so this one will be '0'.

Marcus
  • 6,701
  • 4
  • 19
  • 28
  • 3
    What is the significance of the value 48 added to y? – Abin Mathew Abraham Feb 01 '16 at 15:57
  • 19
    @AbinMathewAbraham 48 is the ascii code of '0' :) – Marcus Feb 18 '16 at 08:37
  • I am using MAC OS with intel processors. It is supposed to be Little Endian. However, `1` seems to be a special case because when `1` is stored inside the memory, it is in big endian. – code4j Mar 07 '16 at 14:25
  • @code4j That doesn't make any sense. The CPU architecture isn't going to make an exception simply for a specific value. What you are seeing must be a one byte value, in which case endianess makes no difference. To do an endianess test, you must choose a multi-byte value. Intel chips (AFAIK) are little endian. – yano Feb 03 '18 at 21:09
  • 2
    Can you tell me why we can't just use `(char)x == 1` ? Why do we have to get the address, convert it to a `char` pointer and then dereference? Won't this be implicitly done `(char)x` is used? – J...S Dec 28 '18 at 11:57
  • 3
    @J...S I believe `(char)x` would work regardless of endianness. And by _"work"_, I mean it would assign the value `1` to `x`, so it wouldn't be possible to detect the endianness this way. – luizfls Aug 22 '19 at 17:59
  • regarding your response: _"48 is the ascii code of '0'"_. Would it not be useful to update your answer to _"so"_ _`(char*)(&x) == 1, and *y+'0' == '1'`_ ? (nice answer regardless, +1) – ryyker Feb 08 '22 at 13:57
27

The following will do.

unsigned int x = 1;
printf ("%d", (int) (((char *)&x)[0]));

And setting &x to char * will enable you to access the individual bytes of the integer, and the ordering of bytes will depend on the endianness of the system.

phoxis
  • 60,131
  • 14
  • 81
  • 117
  • 2
    No need to declare as unsigned int. signed int also will do because 1 is positive and even if one bit is reserved for sign, it will be 0 anyway for positive numbers. – kadina Jul 06 '16 at 22:01
23

This is big endian test from a configure script:

#include <inttypes.h>
int main(int argc, char ** argv){
    volatile uint32_t i=0x01234567;
    // return 0 for big endian, 1 for little endian.
    return (*((uint8_t*)(&i))) == 0x67;
}
admiring_shannon
  • 904
  • 6
  • 16
14

Thought I knew I had read about that in the standard; but can't find it. Keeps looking. Old; answering heading; not Q-tex ;P:


The following program would determine that:

#include <stdio.h>
#include <stdint.h>

int is_big_endian(void)
{
    union {
        uint32_t i;
        char c[4];
    } e = { 0x01000000 };

    return e.c[0];
}

int main(void)
{
    printf("System is %s-endian.\n",
        is_big_endian() ? "big" : "little");

    return 0;
}

You also have this approach; from Quake II:

byte    swaptest[2] = {1,0};
if ( *(short *)swaptest == 1) {
    bigendien = false;

And !is_big_endian() is not 100% to be little as it can be mixed/middle.

Believe this can be checked using same approach only change value from 0x01000000 to i.e. 0x01020304 giving:

switch(e.c[0]) {
case 0x01: BIG
case 0x02: MIX
default: LITTLE

But not entirely sure about that one ...

user1668559
  • 181
  • 7