开发者

Weird result when using the %d specifier to print an unsigned char in C

开发者 https://www.devze.com 2023-02-12 11:56 出处:网络
It is little bit weird. I just play with the unsigned char type and negative values. I have the following code.

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

  1. When printed as %d its -254 (again 2'c complement)

  2. 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 )

0

精彩评论

暂无评论...
验证码 换一张
取 消