Now we have covered most of the things related to C, but still some interviewer can surprise us by asking some question , which sometimes can confused us.
For ex : One of my friend was asked.
char C = 1; // whether 1 will be stored or 0x31 ( ascii value of 1)
One more question was
char c=30;
for ( ; c<300;c++)
{
printf("%d",c);
}
// What will be the output.
Now in both of these question, we have to understand how number is stored and difference between SIGNED and UNSIGNED number storage.
First we will take only CHAR and INT, since they are easy to understand than FLOAT.
Now , when we do
char c=1;
char c='1';
int c=1;
int c='1';
We have to understand that compiler takes the hexa decimal representation of that number on RHS and then stores it. So irrespective of int or char , 1 will be 0x01 and '1' will be 0x31.
And again while printing the values , convert the binary number representation to hexa-decimal.
And depending on %d or %c, check the int or character representation of the stored hexa number.
So for
char a=1;
char b='1';
int c=1;
int d='1';
printf ("%d %d %d %d",a,b,c,d); // will give 1 49 1 49
Coming to second part. SIGNED vs UNSIGNED.
SIGNED means + and - . By DEFAULT every char and int which we mentioned is SIGNED.
Now taking a machine which stores CHAR in 8 bits and INT in 32 bits.
For UNSIGNED we will have 32 bits for INT...so max value can be from 0 to 2^32 -1 , for CHAR 0 to 2^8 -1.
So what if we store some number in unsigned CHAR which is greater than 255.
Then in that case, the last 8 bits of RHS representation of number will be taking into consideration,
So if we have unsigned char c=256; On printing its value we will see 0 is stored in it.
Since the number 256 binary will be
0001 0000 0000 , and CHAR will consider only last 8 bits we have 0 in there.
You will get WARNING at compile time though, and you can use -Werror option on compilation time, so that you don't skip the warning and get unwanted behavior in your program.
So
unsigned char c=30;
for(;c<300;c+=30)
{
printf("%d",c);
}
// This will give infinite loop, since c value at max can be 255, and once it reaches 270, the actual number stored in C will be
270 = 1 0000 1110 // taking last 8 bits = 14 , so again the loop will run.
Now what if we assign some negative number to unsigned type.
Ex :
char c = -1;
Compiler will first convert -1 to binary, using 2's complement .
After that it will take the last 8 bits of RHS and convert back to char/int representation.
Note while printing the value the 8th bit will not be taking as SIGNED bit.
It will be treated as UNSIGNED only.
SO printf("%d",c) will give us 255.
------------------------------------------------------------------------------------------------------------------
2's complement :
-1
1) remove the negative sign
2) convert the number to binary representation
So we have 0000 0001
3) Apply NOT operation.
1111 1110
4) Add 1 now
1111 1111
------------------------------------------------------------------------------------------------------------------
Now this number will be stored , 0xFF will be stored in UNSIGNED CHAR, since we have defined c as UNSIGNED.
So we are done with the UNSIGNED INT and CHAR.
Now coming to SIGNED ones, In case of SIGNED types the first LHS bit is treated as signed flag,
So
1)signed char c=0x80;
2) unsigned char c=0x80;
%d of both will give as
1) -128
2) 128 // this is quite evident
So how 1) answer came to -128.
Now 0x80 was stored as 1000 0000
When we are doing printf, compiler sees that this is signed bit, so it prints its two complement
number 1000 0000 // first bit is 1 , append - flag when printing
Not operation :0111 1111
add 1
1000 0000 = 128
Run this program and see if you can understand the output which came.
#include<stdio.h>
int main()
{
signed char c;
c= 0x80;
printf("%d\n",c);
c= 8;
printf("%d\n",c);
c= -8;
printf("%d\n",c);
c= 511;
printf("%d\n",c);
c= 255;
printf("%d\n",c);
c= -255;
printf("%d\n",c);
}
Note when dealing with SIGNED number , remember
1) Irrespective of signed or unsigned, every negative number will be stored as 2's complement.
2) While printing, if
the number MSB is 1 and the type is SIGNED. 2's complement will be printed with negative sign
So with SIGNED types, storage and printing values are different, which can be highlighted with below program.
One more interesting question:
#include<stdio.h>
int main()
{
unsigned char c= -8;
signed char d = 0x80;
printf("%d \n",c);
printf("%d \n",d);
signed char e = (char) c&d;
unsigned char f = c&d;
printf("%d\n",c&d);
printf("%d \n ",e);
printf("%d \n ",f);
}
Now the output will be
248
-128
128
128
128
Exp :
in C , we will have 8 complement since it is negative ,
8 = 0000 1000
NOT operation : 1111 0111
Now add 1
1111 1000 = 248 , since it is unsigned, 248 will be printed, which is also which is in STORAGE at memory for this
In d we have 1000 0000 ( In STORAGE)
when it is printed, since MSB is 1 , its 2 complement is taken as it is SINGED.
hence, 0111 1111
add 1 1000 0000 128 and add negative sign -128.
Now when we perform & operation, we are doing operation on
1111 1000 and 1000 0000 , since these values are in storage, so we get
1000 0000 which is 128.
Now when we perform any operation between SIGNED and UNSINGED , the result is UNSIGNED.
hence we get 128 , but when we cast it to signed variable , again 2's complement of 0x80 will be printed , hence -128.
What if we have used + operation instead of & operation. Try to work out.
And also what about the - operation. HINT : - operation is nothing , but telling compiler that the number is negative, so a-b becomes more like a + (b 2 complement).
----------------------------------------------------------------------------------------------------------
While making - program, I got one thing, which was bit puzzling.
Ex :
unsigned char c = -8;
signed char d = 0x80;
unsigned char e= c-d;
printf("%d",e);
printf("%d,c-d);
The output were 120 and 376.
120 is quite eveident.
C will be in memory store as 0XF8 .
and D will be 0x80.
Now when we do c-d ...its like c+ (d 2 complement) which is again 0x80.
So e will be 1 0111 1000 , but since e is just 8 bits so we have 0111 1000 = 120.
But when we do printf("%d",c-d), printf sees %d and treat c-d as SIGNED INT , hence we get 1 0111 1000 value which is 376.
-------------------------------------------------------------------
Similarly ,
signed char d = 0x80;
signed char e = -0x80;
printf("%d", -d );
printf("%d", e );
The value will be different, try to figure it out.
So to summarize:
Every negative number gets saved as 2 complement.
While printing , it is checked is number is signed or unsigned.
While operations , the value at the storage is taken into consideration.
No comments:
Post a Comment