Reputation: 233
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
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
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