It is little bit weird. I just play with the unsigned char type and negative values. I have the following code.
开发者_如何学编程#include <stdio.h>
int main(int argc, char* agrv[]){
unsigned char c = -3;
printf("%d, %u, %d, %u\n", c, c, ~c, ~c);
}
The output is,
253, 253, -254, 4294967042
I can not figure out the last three values. What does %d and %u really do?
The %d
format prints out an int
, and %u
prints out an unsigned int
. All arithmetic on unsigned char
values is done by first casting them to int
and doing the operations on int
values, and so ~c
(which is equal to -1 - (int)c
) will return a negative int
value. An explicit cast would be needed to get the unsigned char
result before printing it out (and the call to printf
would cast it back to int
anyway).
"%d" prints as a signed number, %u prints as an unsigned number.
char
gets promoted to int
when you pass it to printf
. printf
will typically take whatever value happens to be on the stack, and interpret it as the type you've specified with your format. On a typical machine (apparently including yours) that means it treats the bit pattern as two's complement.
c is 11 11 11 01 (2's complement) 1. when printed as signed integer(%d) it interprets 32 bits of c 00000000-00000000-00000000-11111101 which equal to decimal 253. 2. %u also prints same as above number (word) is positive.
~c is 1111111111-11111111-11111111-00000010
When printed as %d its -254 (again 2'c complement)
Above number when interpreted as unsigned (255*256^3 + 255 *256^2 + 255*256 + 2) its equal to 4294967042.
Well, I would not go till the printf(). I would rather stop at:
unsigned char c = -3;
And question the purpose of such an initialization which is self contradictory - using -3 to initialize an unsigned char.
-3 is a signed integer. If sign magnitude / ones' complement / two's complement are used to represent this value, then -3 (int) requires more than one byte for the representation. This value, when assigned to an unsigned char will cause an overflow which produces undefined behavior.
step by step explanation:
line -1) unsigned char c = -3;
line -2) 2.1 printf("%d\n ,c);
2.2 printf("%u\n",c);
2.3 printf("%d\n ,~c);
2.4 printf("%u\n",~c);
line-1
Step-1) as assignement is used, so we will first try to evaluate the RHS. In RHS, we have -3. Now -3 is basically an integer constant stored in 32 bits (Assuming 4 bytes for int). SO here first we will calculate how -3 will be stored in memory. As its a negative number, so 2's complement representation will be used for storing -3 in memory. So -3 in memory is 11111111 11111111 11111111 1111 1101
Step-2) Now this -3 will be stored into char c. As char is of 1 byte only. So only lower 8 bits will be read into char c.
Now c is 1111 1101
line-2: 2.1 printf("%d\n ,c);
Step-1: At this point, we are trying to print the char variable, c using %d. So whenever a char variable is used in expressions, it gets promoted to int first then its value is used or printed. Lets promote 8 bit char to 32 bit int. In this promotion, 8 bits of char will be copied onto lower order 8 bits of a 32 bit integer number. Hence 32 bit number is -------- -------- -------- 1111 1101
Now the question is how to fill the initial 24 bits? These bits will be filled as per the following rules
Rule 1: If the char is of type unsigned char then simply fill all the 24 bits with 0.
Rule 2: If the char is signed char, then check the MSB of char (left most bit of 8-bit number). If this bit is 1, then fill the 24 bits with 1's. If this bit is zero then fill with zeros.
Step 2: As in our case, the char is of unsigned type, so initial 24 bits will filled using 0's. Now the 32 bit version of c is 00000000 00000000 00000000 1111 1101
Step 3: Now while printing using %d, check MSB of this 32 bit number c. MSB is 0 means this is a positive number. Calculate its magnitude, which is 253.
2.2 printf("%u\n ,c);
Step-1: As explained above after promotion to 32 bit integer, c holds the following bits: 00000000 00000000 00000000 1111 1101. This promotion happens because of integral promotion of a char before any use of char variable with integers.
Step-2: As we are printing it using %u, it will consider it as an unsigned number and simply calculate the magnitude, which is 253.
2.3 printf("%d\n ,~c);
step-1: binary inside c = 00000000 00000000 00000000 1111 1101 (after promotion)
Step-2: perform bit-wise complement of c: 11111111 11111111 11111111 0000 0010
Step-3: print using %d: As MSB=1, so this is a negative number. Calculate 2's complemnt to find the magnitude of this number.
2's complement is 00000000 00000000 00000000 1111 1110
in decimal this number is -254
2.4 printf("%u\n ,~c);
Step-1: c is 00000000 00000000 00000000 1111 1101
Step-2: bit-wise complement of c: 11111111 11111111 11111111 0000 0010
Step-3: print using %u, as %u is for printing unsigned numbers, printf will conside ~c as an unsigned number and will calculate the magnitude accordingly. Hence the magnitude is 4294967042 (4,294,967295 - 253 )
精彩评论