0

When creating a union of an unsigned integer and a 4 byte array in c, the order of the bytes seem to be reversed. Why is this?

For an integer with binary representation 10000000 00000000 00000000 00000000, I would expect b[0] = 10000000, b[1] = 00000000 etc..

#include <stdio.h>
#include <stdlib.h>

typedef union intByteRep{
    unsigned int i;     // 00000000 00000000 00000000 00000000
    unsigned char b[4]; //   b[0]     b[1]     b[2]     b[3]  - What we would expect
                        //   b[3]     b[2]     b[1]     b[0]  - What is happening  
} intByteRep;

char *binbin(int n);

int main(int argc, char **argv) {

    intByteRep ibr;
    ibr.i = 2147483648; // 10000000 00000000 00000000 00000000

    for(int i = 0; i < 4; i++){
        printf("%s ", binbin(ibr.b[i]));
    }
    printf("\n"); // prints 00000000 00000000 00000000 10000000

    for(int i = 3; i >= 0; i--){
        printf("%s ", binbin(ibr.b[i]));
    }
    printf("\n"); // prints 10000000 00000000 00000000 00000000

    return 0;
}

/*function to convert byte value to binary string representation*/
char *binbin(int n)
{
    static char bin[9];
    int x;
    for(x=0; x<8; x++)
    {
        bin[x] = n & 0x80 ? '1' : '0';
        n <<= 1;
    }
    bin[x] = ' ';
    return(bin);
}
Govind Parmar
  • 20,656
  • 7
  • 53
  • 85

3 Answers3

2

because your system is little endian.

32 bit integer 0x11223344 is stored in memory 0x44 0x33 0x22 0x11

on the big endian system it would be stored as : 0x11 0x22 0x33 0x44

BTW most of the popular uP are little endian.

0___________
  • 60,014
  • 4
  • 34
  • 74
2

The order in which bytes are stored in memory is a function of the endianness on your platform. In this case, your system is little-endian, so you are observing that the bytes at higher addresses of the int they constitute contain the most significant bits (which, in your example of 2147483648, is a single 1 bit at the most significant digit).

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
1

In the days when computers were often called upon to process numbers larger than what they could handle in a single step, addition and subtraction would generally require that the computer process the lower-order portions of the number first, much as one would process numbers by hand. If one is adding 123 to 678 and starts by adding the last digit of each addend (3 and 8), one will be able to determine the last digit of the result 1, write it down, and forget about it beyond the fact that there was a carry, before one has to even look at any other portions of the addend. One can then add the middle digits with the carry from the preceding number, and know that the middle digit of the result is 0 without having to look at the first digit of either operand. One can then compute the first digit of the result.

If one had started by adding the 1 to the 7, one wouldn't be able to write the first digit of the result with certainty until one had processed the second and third digit as well. Thus, one would either have to keep track of all digits until one had finished the computation, or be willing to write down an incorrect result from earlier digits and then adjust them if there's a carry. Not as nice or efficient.

While it would be possible to store things in memory with the larger digit first, but still perform calculations starting at the small end, address calculations tend to be more efficient if an object's address directly identifies the first part of it that will be used. Thus, most systems store the least significant part of each object in memory before the more significant parts.

supercat
  • 77,689
  • 9
  • 166
  • 211