Address and byte ordering

For programs objects that span multiple bytes it’s necessary to establish two conventions:

  • what is the address of the object
  • how to order the bytes in memory

In virtually all machines this object is stored as a contiguous sequence of bytes, where the address is the smallest address of the byte used. This can be checked with this C code:

#include <stdio.h>
int main()
{
int i = 132997692;
int *ptr = &i;
printf("Address of pointer: %p\n", (void *)&ptr);
for (int byte_offset = 0; byte_offset < sizeof(int); byte_offset++)
{
printf("Byte %d at address %p contains: %x\n", byte_offset, (void *)((char *)ptr + byte_offset), *((unsigned char *)ptr + byte_offset));
}
return 0;
}

It prints:

Address of pointer: 0x16ce26d60
Byte 0 at address 0x16ce26d68 contains: 3c
Byte 1 at address 0x16ce26d69 contains: 62
Byte 2 at address 0x16ce26d6a contains: ed
Byte 3 at address 0x16ce26d6b contains: 7

Visual representation (of another number):

Memory

Some machines use a different order:

  • least to most: referred to as little endian
  • most to least: referred to as big endian

This byte ordering is totally irrelevant, one is not better than the other. Little endian is used almost everywhere. For application programmers the order is totally invisible, compilers will deal with that stuff. However, ordering matters when sending sending binary data over the network. A common problem is for data to be sent by a little endian machine to be read by a big endian, or vice versa. This leads to problem. Code written for networking applications must follow established conventions for byte ordering to make sure the sending machine converts its internal representation to the network standard, while the receiving machine converts the network standard to its internal representation.

Another program

#include <stdio.h>
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, size_t len)
{
for (int i = 0; i < len; i++)
{
printf(" %.2x", start[i]);
}
printf("\n");
}
void show_int(int x)
{
show_bytes((byte_pointer)&x, sizeof(int));
}
void show_float(float x)
{
show_bytes((byte_pointer)&x, sizeof(float));
}
void show_pointer(void *x)
{
show_bytes((byte_pointer)&x, sizeof(void *));
}
void test_show_bytes(int val)
{
int ival = val;
float fval = (float)ival;
int *pval = &ival;
show_int(ival);
show_float(fval);
show_pointer(pval);
}
int main()
{
test_show_bytes(12345);
}

Output:

39 30 00 00
00 e4 40 46
58 6d 5d 6b 01 00 00 00
Back to notes