mary korah
mary korah

Reputation: 13

union and structure memory sharing

I was trying to find the answer of a question which involves two structures inside a union.

I have typed the question in online debugger the answer which I am finding and the real answer is not giving hands to each other. Can somebody help me out with the answer with explanation.

#include <stdio.h>

int main()
{
    union{
            struct{
                       char c[2];
                       char ch[2];
                  }s;
           struct {
                       short int i;
                       short int j;
                 }st;
       }u={12,1,15,1};

  printf("%d%d",u.st.i,u.st.j);
}

answer is 268 and 271

Upvotes: 1

Views: 72

Answers (2)

0___________
0___________

Reputation: 67546

Decimal numbers are not very good for this kind of tests. You should also enable all warnings as well. If you do so you will get

<source>:25:8: warning: missing braces around initializer [-Wmissing-braces]

So let's rewrite your program a little bit:

int main()
{
    union
    {
        struct
        {
            char c[2];
            char ch[2];
        }s;
        struct 
        {
            short int i;
            short int j;
        }st;
    }u={.s = {{0x12,0x01},{0x15,0x01}}};  //better to show compiler what you want to initialize

  printf("%04hx %04hx",u.st.i,u.st.j);
}

And the result is:

0112 0115

clearly showing the numbers we have used in the initialization. The numbers show us that this system uses little endian system where the least significant byte is placed first.

You should be avare that compiler is free to add any padding needed. To avoid it you have to use compiler extensions - structure packing.

Upvotes: 1

Lundin
Lundin

Reputation: 213892

  • Start by making more sense of this by swapping to hexadecimal: {0xC,0x1,0xF,0x1}. This allows us to view the bytes as they are stored in memory, without worrying about converting to/from decimal base.
  • When initializing a union, the first member gets initialized, in this case the struct s.
  • It would be cleaner to write { {{0xC,0x1}, {0xF,0x1}} } but unfortunately C allows omitting the curly braces of inner structs/arrays, allowing us to put sloppily written crap in our initialization lists just because we can.
  • The memory order of a char byte array is always top to bottom on any system: first byte on least significant address. That is: 0xC 0x1 0xF 0x1.
  • Strictly speaking, the compiler is free to add struct padding bytes anywhere between the struct/union members, to compensate for misalignment. Doesn't happen in this specific case, but it would happen if we for example used char c[3].
  • When you "type pun" this memory area using shorts, they get read according to endianess, since short is larger than 1 byte and an integer type.
  • On a little endian CPU you would therefore get each short to assume that 0xC is the least significant byte and so the first short ends up as 010C hex.

If we translate your code to hex, it should be clearer:

#include <stdio.h>

int main()
{
    union{
            struct{
                       char c[2];
                       char ch[2];
                  }s;
           struct {
                       short int i;
                       short int j;
                 }st;
       }u={ {{0xC,0x1}, {0xF,0x1}} };

  printf("%.4X\n%.4X",u.st.i,u.st.j);
}

Output on little endian CPU:

010C

010F

10Ch = 268d and so on.

Upvotes: 1

Related Questions