SanQA
SanQA

Reputation: 233

Memory allocation for union in C

I was recently studying union and end up with a confusion even after reading a lot about it.

#include<stdio.h> 
union test
{
    int x;
    char arr[4];
    int y;
};

int main()
{
    union test t;
    t.x = 0;
    t.arr[1] = 'G';
    printf("%s\n", t.arr);
    printf("%d\n",t.x);
    return 0;
}

What I understood is :

Since x and arr[4] share the same memory, when we set x = 0, all characters of arr are set as 0. 0 is ASCII value of '\0'. When we do "t.arr[1] = 'G'", arr[] becomes "\0G\0\0". When we print a string using "%s", the printf function starts from the first character and keeps printing till it finds a \0. Since the first character itself is \0, nothing is printed.

What I don't get is second printf statement

Now since arr[] is "\0G\0\0" , the same location is shared with x and y. So what I think x to be is the following

00000000 01000111 00000000 00000000 ("\0G\0\0")

so t.x should print 4653056. But what it's printing is 18176.

Where am I going wrong?

Is this technically undefined or is it due to some silly mistake or am I missing some concept??

Upvotes: 4

Views: 4728

Answers (2)

Achal
Achal

Reputation: 11921

All members of Union will share the same common memory. assume starting address of union is 0x100. when you wrote t.x = 0; whole 4 bytes got initialize with zero as

-------------------------------------------------
| 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000  |
-------------------------------------------------
0x104     0x103       0x102        0x101        0x100
                                                 x,arr,y 

when you are writing t.arr[1] = 'G'; arr[1] will overwritten with 'G' ascii value, it looks like

-------------------------------------------------
| 0000 0000 | 0000 0000 | 0100 0111 | 0000 0000  |
-------------------------------------------------
0x104     0x103       0x102        0x101        0x100 

now calculates this value which is 18176.

Upvotes: 9

Tals
Tals

Reputation: 478

tl;dr: endianity!

When printf reads the data from the memory pointed at by your union, it looks at the endianity of your system and reads the data stored in little endian. So, instead of printing the data as it is stored in memory (0x00470000) it gets the number 0x00004700, which correlates to 18176, like you get.

Code example:

#include<stdio.h> 
union test
{
    int x;
    char arr[4];
    int y;
};

int main()
{
    union test t;
    t.x = 0;
    t.arr[1] = 'G';
    printf("%s\n", t.arr);
    printf("%d\n",t.x); // prints 18176

    t.x = 0;
    t.arr[2] = 'G';
    printf("%d\n",t.x); // prints 4653056
    return 0;
}

Or in Python:

import struct

union_data = "\x00G\x00\x00"
print struct.unpack("<I", a)[0] # This is little endian. Prints 18176
print struct.nupack(">I", a)[0] # This is big endian. Prints 4653056

Bonus! You can also use the function htonl to convert integers read as little endian to big endian. See more at the docs.

Upvotes: 2

Related Questions