C语言scanf、printf中%u接收short、int、unsigned负数的情况出现的异常

一、前提知识:

注:部分来源于互联网(该部分非原创)

计算机内存数值存储方式是补码

原码

一个数的原码原始的二进制码)最高位做符号位,0表示该数为,为1表示为负数。剩下的位就是数值绝对值的二进制数所以负数的原码是在其绝对值的基础上,再加一个最高位1原码方便人理解,当两个正数相减或不同符号数相加时即十进制加减法计算后如果可能产生负数结果时,必须比较两个数绝对值大小,才能决定谁减谁并且确定结果是正还是负,所以原码不便于直接加减运算。

反码

正数反码与原码相同负数的反码是其原码的符号位不变,剩下部分取反(10互变)反码计算也同样不方便(因为还是存在符号位)

 补码

正数原码、反码、补码全部相同负数的补码是其反码加1所以负数的补码是其原码符号位不变,剩下部分取反最后整个数加1得到补码

补码符号位不动,其他位求反,最后整个数加1,得到原码

在计算机系统中,数值用补码来存储,主要原因是:

  • 可以统一0的编码
  • 可以把符号位和其它位统一处理
  • 两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃

不管以原码方式存储,还是以反码方式存储,0两种表示形式即-0与+0
但是如果以补码方式存储+0是原码、反码、补码相同,都是全0,;-0原码是10000000(以8位二进制数为例),将其1舍去。

总结

有符号数=1位符号位+n-1位数据位

无符号数=n位数据位

二、int、unsigned int型负数

12345的二进制表达为11 0000 0011 1001

若定义一个int型变量a,则a在内存空间中占32bits。

-12345以补码的方式存在计算机里面,即1111 1111 1111 1111 1100 1111 1100 0111。

a=-12345u即把a的空间里填上补码1111 1111 1111 1111 1100 1111 1100 0111。

读取若以unsigned的方式去读取(%u)即不考虑符号位,直接把补码1111 1111 1111 1111 1100 1111 1100 0111这个二进制数转换成十进制,也就是4294954951。

但是以signed方式读取(%d)就会考虑符号位,还是-12345。

所以把a定义为unsigned型数据也和定义为int的结果一样

另外-12345不带u和带u的结果一样。

三、short型负数

53191是-12345(默认int型)在计算机里的补码1111 1111 1111 1111 1100 1111 1100 0111截取最小的16位直接转换成十进制得到53191。

我之前认为

short a;

a=-12345u;

printf(“%u”,a);

应该打印出来53191。

但是

 

其实是因为%d输出会把short的16位自动补齐为32位

补齐规则是看最高位:如果最高位为0,就把最高的16位都补为0;如果....1.....补为1.....,然后再输出。

所以是把截取的1100 1111 1100 0111补齐为1111 1111 1111 1111 1100 1111 1100 0111,也

就是4294954951与-12345。

如果用-123456:

因为123456的二进制形式是1 1110 0010 0100 0000(共17位大于short的16位),

所以常数-123456(是int型),补码即为1111 1111 1111 1110 0001 1101 1100 0000

而a是short所以只截取了后16位0001 1101 1100 0000,所以不论是%d还是%u都是补齐为0000 0000 0000 0000 0001 1101 1100 0000,即7616。

而且a的size不会因为-123456后加了u还是l而改变。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值