Search code examples
cswapendiannessunions

Endian Swap in C Union


I am trying to understand the way an endian swap works when done within a union in C. I understand that a union has the ability to hold multiple types of data, but can only hold one type at a time. The code I am trying to understand looks like this, this is the union definition:

  union byte4 {
          char byte[4];
          int numint;
          float numfloat;
  };

This is the function.

  int endianSwap4int(int a) {
      union byte4 un;
      un.numint = a;

      // swap
      char c1 = un.byte[0];
      un.byte[0] = un.byte[3];
      un.byte[3] = c1;
      c1 = un.byte[1];
      un.byte[1] = un.byte[2];
      un.byte[2] = c1;

      return un.numint;
  }

In the function, if the input a is 2048327680, the function returns 6010 when un.numint is returned. I understand that manipulating un.byte is indirectly manipulating un.numint as well because unions can only hold one thing at a time, but I don't understand exactly how they affect each other, so my question is, how exactly do they affect each other?


Solution

  • If you look at the hex representation of 2048327680, you'll see it is 7A 17 00 00. So if your machine stores this value in little endian format, the LSB is stored first.

    If we add extra debugging to endianSwap4int as follows:

      int endianSwap4int(int a) {
          union byte4 un;
          int i;
          un.numint = a;
    
          printf("before:\n");
          for (i=0;i<4;i++) {
              printf("un[%d]=%02X\n", i, un.byte[i]);
          }
    
          // swap
          char c1 = un.byte[0];
          un.byte[0] = un.byte[3];
          un.byte[3] = c1;
          c1 = un.byte[1];
          un.byte[1] = un.byte[2];
          un.byte[2] = c1;
    
          printf("after:\n");
          for (i=0;i<4;i++) {
              printf("un[%d]=%02X\n", i, un.byte[i]);
          }
          return un.numint;
      }
    

    You'll see the following output:

    before:
    un[0]=00
    un[1]=00
    un[2]=17
    un[3]=7A
    after:
    un[0]=7A
    un[1]=17
    un[2]=00
    un[3]=00
    

    Here, you can see that the LSB of the original number is first before the swap, and the MSB of the original number is first after the swap. So now the int portion of the union contains the value 00 00 17 7A which in decimal is 6010.