浅谈 用无符号字符型定义一个正数或负数a, 然后用printf的%d与%u输出其 -a 的值

浅谈 用无符号字符型定义一个正数或负数a,

然后用printf的%d与%u输出其 -a 的值

因为%u可以输出unsigned int unsigned short 和unsigned char
故猜想%u将内存中的数据先转化为4字节,再按照二进制数据进行无符号处理并输出。该猜想在下面实例中得以验证。

以下内容所涉及到的长短数据扩展请参考细文:http://blog.sina.com.cn/s/blog_6adcb3530101cmsd.html

这里我们简单讲述下输出a时的情况,为下面输出-a作铺垫。

这里写图片描述

如图中定义的unsigned char a =169。先将169转化为对应的二进制数,也就是 1010 1001 由于169为正数,所以它的原码应该为0 1010 1001 。故它的补码等于它的原码0 1010 1001。由于unsigned char类型为1字节8位,故将169的补码取出后8位舍去最高位的符号位 0 ,存储在a这个无符号字符型变量中。
故a存储的是1010 1001(169的8位数补码)
在直接以%u输出a的过程中:
a存储的补码 1010 1001 可如何将这个1字节数据,以4字节输出呢?这时要把1字节拓展为4字节:
这里写图片描述

//1010 1001  扩展-> ???? ???? ???? ???? ???? ???? 1010 1001"?"处为尚未填充区)
//由于从unsigned char类型扩展到int时,填充区的值都是0(如见上图unsigned char转化为long类型)
//故扩展之后的4字节unsigned char a 的补码为:  0000 0000 0000 0000 0000 0000 1010 1001 

当%u与%d接受到这个补码时:
%u当做无符号类型解析: 该补码 0000 0000 0000 0000 0000 0000 1010 1001 32位全为数值位,并且为无符号类型解析,则该补码就是其a扩宽后的原码。
而%u是以十进制输出的,故该数值为这个32位二进制数的十进制数值:169;
%d当做有符号类型解析: 该补码0000 0000 0000 0000 0000 0000 1010 1001,在%d面对它时,会将其的第一个二进制位看作是符号位,在这里也就是 0 ,其后面的31位将作为数值位。而%d以十进制输出,故该31位的二进制数的十进制数值为:169,由于符号位为0,表示为正数。继而%d输出a为:169。

这里开始重点讲一下,如果printf输出的是 -a 的情况
这里写图片描述

同样的,当数据即将传给printf之前,a在内存中存储的169补码为 1010 1001
传入printf
%d与%u解析之前: 要将-a传递给%d与%u,就先要将-a表示出来。这时要在a所存储的补码前面加一个符号位” 1 “用来为表示 -a 做准备 ,则现在为: 1 1010 1001 之后,怎样将这个二进制数据转为 -a 的呢?这里可能是将加符号位后的二进制:1 1010 1001 看成是“ -a ” 的原码,然后要将“ -a ”的这个原码转换为补码后,传递给%u与%d。 由于-a 原码的符号位为“ 1 ”,故其补码为1 0101 0111 (符号位不动,其它8位取反为“1 0101 0110 ”后 +1 成为 ” -a “的补码 )
之后将这个补码扩宽到32位( -a 相当于一个新char“带符号类型”,所以扩宽的时候以符号位填充)
由于符号位为“ 1 ”,故4字节补码表示为:1 111 1111 1111 1111 1111 111 1 0101 0111

现在将这个补码分别以%u和%d输出:
%u十进制输出时: 由于%u解析的时候不考虑符号位,故该32位全为数值位,由于%u考虑的无符号类型,故%u认为这是一个正数,即原码=补码。故%u输出的是该32位所代表的数值: 4294967127
%d十进制输出时: 由于%d解析的时候要考虑符号位,并且要将补码转换为原码输出。 则步骤如下:
补码减一后,符号位不变,其它31位取反,继而原码为:1 000 0000 0000 0000 0000 000 0 1010 1001 该31位二进制数值与其符号位输出的是:-169;

总结以上规律,得有以下结论:在unsigned char定义一个整数或负数a时,面对以%u与%d输出 -a ,有以下步骤:
1:对unsigned char变量所存储的补码加一个符号位,该符号位的数值为“ 1 ”(可能是用其表示负号而添加的)
2:对于这个新的二进制数据,把它当做新数据(比如-a)的原码,然后转化为补码。
3:进行短数据扩宽(加入符号位1后类似于一个char类型,填充时以“ 1 ”进行填充)
4:按照 %u还是 %d,以对应规则,转化为原码并输出其十进制。
注意:上面是输出 -a(无论a为正为负),而输出a时,在截断8位数据后的补码直接进行填充,并按百分号类型输出
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
现将上面的结论再应用于实践中验证一下。

这里写图片描述


a=-69

-69的原码为: 1100 0101 (第一个1为符号位)
由于符号位为1 ,故取其补码: 1011 1011 则a存储的补码为: 1011 1011

输出a
a的补码被填充后为0 000 0000 0000 0000 0000 0000 1011 1011(按unsigned char扩展为 int,全部填充0)
扩展填充0后,第一位0相当于新符号位,原来的符号位成为了一个数值位,故%d与%u输出同为:187
(补码=原码= 0 000 0000 0000 0000 0000 0000 1011 1011)

输出 -a
传入printf:应用结论第一步:在第9位加入一个符号位 1 1011 1011
第二步: 将这个二进制数据当作一个新原码,则它的补码为:1 0100 0101
第三步:按照char 到 int 类型扩展:1 111 1111 1111 1111 1111 111 1 0100 0101
第四步 %u 将该32位二进制数据转化为十进制为: 4294967109
%d 将该补码换成原码为:1 000 0000 0000 0000 0000 000 0 1011 1011 输出为:-187


a=-169

这里写图片描述

-169的原码为: 1 1010 1001(第一个1为符号位)
由于符号位为1 ,故取其补码: 1 0101 0111 则a存储的补码为: 0101 0111 (截取8位,符号位溢出)

输出a
a的补码被填充后为0 000 0000 0000 0000 0000 0000 0101 0111(按unsigned char扩展为 int,全部填充0)
扩展填充0后,第一位0相当于新符号位,原来的符号位成为了一个数值位,故%d与%u输出同为:87
(补码=原码= 0 000 0000 0000 0000 0000 0000 0101 0111)

输出 -a
传入printf:应用结论第一步:在第9位加入一个符号位 1 0101 0111
第二步: 将这个二进制数据当作一个新原码,则它的补码为:1 1010 1001
第三步:按照char 到 int 类型扩展:1 111 1111 1111 1111 1111 111 1 1010 1001
第四步 %u 将该32位二进制数据转化为十进制为: 4294967209
%d 将该补码换成原码为:1 000 0000 0000 0000 0000 000 0 0101 0111 输出为:-87


a=69

这里写图片描述

69的原码为: 0100 0101(第一个0为符号位)
由于符号位为0 ,故其补码=原码:0100 0101

输出a
a的补码被填充后为0 000 0000 0000 0000 0000 0000 0100 0101(按unsigned char扩展为 int,全部填充0)
扩展填充0后,第一位0相当于新符号位,原来的符号位成为了一个数值位,故%d与%u输出同为:69
(补码=原码= 0 000 0000 0000 0000 0000 0000 0100 0101)

输出 -a
传入printf:应用结论第一步:在第9位加入一个符号位 1 0100 0101
第二步: 将这个二进制数据当作一个新原码,则它的补码为:1 1011 1011
第三步:按照char 到 int 类型扩展:1 111 1111 1111 1111 1111 111 1 1011 1011
第四步 %u 将该32位二进制数据转化为十进制为: 4294967227
%d 将该补码换成原码为:1 000 0000 0000 0000 0000 000 0 0100 0101 输出为:-69



本文考虑的四种情况是:

169(8位存储的最高位被数值位1占用(符号位的0被溢出))
-169(8位存储的最高位被数值位1占用(且符号位的1被溢出))
69(8位存储数值位没有达到最高位(符号位为0且未被溢出))
-69(8位存储数值位没有达到最高位(符号位为1且未被溢出))

初学者拙见,有错误的地方望指正。

猜你喜欢

转载自blog.csdn.net/qq_42873341/article/details/82560607