To understand the logic behind the behavior, its good to have understanding of union. This is described below under "Understanding Union". For the user who know this or directly want to go through the rational refer "Rational Behind Behavior".
Understanding Union
Similar to structure, union is a way to create a user defined data type which can hold variables of different types and size. But the difference is the size of a structure is aggregate of size of all variables present in a structure (considering memory alignment) and every variable hold different memory location, whereas size of union is same as size of its widest member and a same memory location is shared by all members.
The variables of a union can also be accessed the way variables of a structure are accessed, i.e.,
<union name>.member
or
<union pointer name>->member
Consider below code:
#include "stdio.h"
struct s {
int i;
char *p;
};
union u {
int i;
char *p;
};
int main() {
struct s svar = { 0 };
union u uvar = { 0 };
char c = 0;
svar.p = &c;
uvar.p = &c;
printf("Structure size: %d\n", sizeof(svar));
printf("Union size: %d\n", sizeof(uvar));
printf("i of structure: %d\n", svar.i);
printf("i of Union: %d\n", uvar.i);
printf("Address of c: %d\n", &c);
return 0;
}
The output of code is similar to:
Structure size: 8
Union size: 4
i of structure: 0
i of Union: 2293459
Address of c: 2293459
From the code and its output it can be noticed that:
1. The structure and union contain same variable but the size of structure and union is different. Structure occupies 8 bytes (aggregate of size of int and pointer to char). Whereas union occupies only 4 bytes (both int and pointer to char need 4 bytes and memory is shared between them).
2. We assigned the same address of variable 'c' to char pointers of structure and union. When we output the value of variable 'i' of structure, it is '0', i.e., the value assigned during initialization has not got modified because all variables of structure hold different memory location. Whereas when we output the value of variable 'i' of union, it is same as the address of variable 'c' assigned to variable 'p' of union. This is because the memory is shared between the variables of union.
Rational Behind Behavior
Let's discuss the actual problem statement now.
The code in the given problem statement is:
void main()
{
union
{
int a;
struct
{
char b;
char c;
}ch;
}num;
num.a=0;
num.ch.c++;
printf("%d",num.a);
}
Here the union defined is:
union {
int a;
struct {
char b;
char c;
} ch;
};
For the above union, the memory will be shared between the integer variable 'a' and structure variable 'ch'.
On a 32-bit machine, integer variable 'a' will take 4 bytes and the structure 'ch' will take 2 bytes. So the sharing of the memory will be as:
Variable a : MSB-> XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX <-LSB
Variable ch: MSB-> XXXXXXXX XXXXXXXX <-LSB
char c char b
Consider the given case. When we assign '0' to variable 'a' the above shared memory will look like:
Variable a : MSB-> 00000000 00000000 00000000 00000000 <-LSB
Variable ch: MSB-> 00000000 00000000 <-LSB
char c char b
And when we increment variable 'ch.c' by '1', the changes in shared memory will look like:
Variable a : MSB-> 00000000 00000000 00000001 00000000 <-LSB
Variable ch: MSB-> 00000001 00000000 <-LSB
char c char b
The decimal equivalent of binary value "00000000 00000000 00000001 00000000" is 256. Hence on incrementing 'ch.c' by one the value of 'a' got incremented by 256.
Consider one more increment in 'ch.c', the changes in shared memory will look like:
Variable a : MSB-> 00000000 00000000 00000010 00000000 <-LSB
Variable ch: MSB-> 00000010 00000000 <-LSB
char c char b
The decimal equivalent of binary value "00000000 00000000 00000010 00000000" is 512. Hence each increment in 'ch.c' increment the value of 'a' by 256.
Consider a case when we increment 'ch.b' instead of 'ch.c', the changes in shared memory will look like:
Variable a : MSB-> 00000000 00000000 00000000 00000001 <-LSB
Variable ch: MSB-> 00000000 00000001 <-LSB
char c char b
The decimal equivalent of binary value "00000000 00000000 00000000 00000001" is 1. Hence each increment in 'ch.b' increment the value of 'a' by 1.
The case can be extended to a union where the structure ch is having three character variables as:
union {
int a;
struct {
char b;
char c;
char d;
} ch;
};
For the above union the sharing of the memory will be as:
Variable a : MSB-> XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX <-LSB
Variable ch: MSB-> XXXXXXXX XXXXXXXX XXXXXXXX <-LSB
char d char c char b
Here if we initially assign '0' to variable 'a' and then increment variable 'ch.d' by 1, the memory will look like:
Variable a : MSB-> 00000000 00000001 00000000 00000000 <-LSB
Variable ch: MSB-> 00000001 00000000 00000000 <-LSB
char d char c char b
The decimal equivalent of binary "00000000 00000001 00000000 00000000" is 65536, hence incrementing 'ch.d' by 1 will increment the value of 'a' by 65536.
Let me know if any item need more clarification.
-Pradeep