4

Consider the following code:

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char *argv[]) {
    uint16_t num = 123;

    if (htons(num) == num) {
        printf("big endian\n");
    } else {
        printf("little endian\n");
    }
}

I'm wondering whether this code works for checking endianness? I've seen many questions checking it with various pointer/char tricks, but I figure this is simpler. It works off the assumption that if you convert a number to network-byte order (big endian), if it is the same as the original number then you're on a big endian system. Otherwise you're on a little endian system.

Is there a false assumption in this check? Perhaps maybe network-byte order isn't always big endian, though it seems it is standardised to be so.

Daniel Porteous
  • 5,536
  • 3
  • 25
  • 44
  • Note I don't have a big endian machine lying around to check this code on, and attempts at emulating such a system are proving unfriendly. – Daniel Porteous Dec 30 '16 at 03:34
  • If you want to be completely thorough, the assumption here is that the byte order is either big endian or little endian. There have been architectures that used other byte orders (e.g., the PDP-11 stored the 32-bit value 0x01020304 as 0x02 0x01 0x04 0x03). Obviously, there are only two possibilities for storing a 16-bit value. – Andy Schweig Dec 30 '16 at 03:56
  • The actual question is: why do you care at all? `htons` & friends are exactly meant to have the user not care about endianess. Code onm hosted environments which relies on a specific endianess is generally broken by design. – too honest for this site Dec 30 '16 at 04:07
  • It's for an exercise from Advanced Programming in the Unix Environment, in which it asks for code to determine the endianness. My answer was this code, whereas they did one of the regular bit tests. I just wanted to confirm that I was correct. – Daniel Porteous Dec 30 '16 at 04:13
  • @DanielPorteous - If you want access to one, send your `authorized_keys` file *noloader, gmail account*. I keep an old PowerMac with a PowerPC online for testing. – jww Dec 30 '16 at 08:30

2 Answers2

7

This is sufficient to check for endianness at run time.

On big endian systems, htons (as well as ntohs, htonl, and ntohl) are defined as no-ops, while on little endian systems they perform a byte swap.

EDIT:

This can also be done using a union. The check below detects big and little endian, as well as other more exotic byte orderings.

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

union echeck {
    uint32_t i;
    char c[4];
} echeck = { .c = { 0x01, 0x02, 0x03, 0x04 } };

int main()
{
    if (echeck.i == 0x01020304) {
        printf("big endian\n");
    } else if (echeck.i == 0x04030201) {
        printf("little endian\n");
    } else if (echeck.i == 0x02010403) {
        printf("pdp endian\n");
    } else {
        printf("other endian\n");
    }
    return 0;
}
dbush
  • 205,898
  • 23
  • 218
  • 273
2

In principle, C allows the bits in the representation of uint16_t to be in any implementation-defined order, not just "little" or "big endian". As written, your test only tells you that htons permutes bits 0,1,3,4,5,6 and 2,7-15 separately without mixing them.

If you iterate over all powers of two and find that htons(1<<i)==1<<i for i in 0..15, then you can conclude that the order is definitely big endian. If you instead find that htons(1<<i)==1<<(i^8) for i in 0..15, you can conclude little endian. Otherwise you have a really unusual representation.

In reality, weird things don't happen and your test should be sufficient.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Yeah this is the kind of complication I was expecting, but as you indicate I wasn't expecting it to be an issue in any reasonable system. Great answer, thanks. – Daniel Porteous Dec 30 '16 at 05:10