有符号与无符号运算笔记

需要了解的知识

1.原码、补码
2.计算机寄存器和内存进行运算的存储方式

知识点

  • 整型数据在内存中是以二进制的补码形式存放的,且最高位为符号位,1表示负数,0表示正数,其它位为数值位。
  • 无符号数与有符号数进行运算时,有符号数将被看作无符号数
  • 原码与补码
    正数的补码是原码,负数的补码是绝对值的原码取反加1
  • %d整型输出(有符号输出),%u无符号整型输出
  • C语言中比int小的整型(包括short 、unsigned short 、 unsigned char和char)在运算中,考虑到运算效率的问题都要转换成int然后进行运算。
  • 字节由短到长时,unsigned低字节直接拷贝,高位补0,signed低字节直接拷贝,高位补符号位;由长到短时,只保留低字节
  • 当编译器以整型输出时(%d),是以补码还原的方式来解读
  • 当CPU进行数据运算时,直接以内存中存储的方式进行运算,即补码的形式
  • 当编译器以无符号整型输出时(%u),就没有符号位的概念了,全部都是数值位,直接转化为十进制输出
  • 计算机输出数据是从寄存器中输出
    运算的过程:寄存器–>cpu–>寄存器
  • 当超出类型范围(即溢出),列如signed char类型:-129的补码为127的原码,-130的补码为126的原码…依次类推。

例案解析

int main(){
unsigned char a = 255;
char b = 255;
printf("%d %u\n",a,a);
printf("%d %u\n",b,b);
return 0;
}
输出结果:
255 255
-1  4294967295

解析:
a是一个无符号字符型数据,且a是一个正数,正数的补码即为原码。在存入寄存器中时高位补0,即0000 0000 0000 0000 0000 0000 1111 1111(32位)。再到CPU中进行运算,之后存入寄存器中,值不变。%d是以补码还原的形式输出,%u是直接以十进制输出。故前者输出的值为255,255。
b是一个有符号字符型数据,且b是一个正数,正数的补码即为原码。在存入寄存器中时高位补符号位,因为1111 1111的最高位为符号位,符号位为1,故前面都补1,即1111 1111 1111 1111 1111 1111 1111 1111。输出时%d补码还原,负数的补码为原码取反+1,得到0000 0000 0000 0000 0000 0000 0000 0001,故为-1。%u以十进制输出,故得到2^32-1。

char c = 250;
unsigned char d;
char f;
d = c + 249;
f = c + 249;
printf("d=%d\n",d);
printf("d=%u\n",d);
printf("f=%d\n",f);
printf("f=%u\n",f);
输出:
d=243
d=243
f=-13
f=4294967283

解析:
250的补码为1111 1010,250为正数且为char型,不足32位,故高位补符号位,存入寄存器中的补码为1111 1111 1111 1111 1111 1111 1111 1010,249为正数且为int型(32位),存入寄存器的补码为0000 0000 0000 0000 0000 0000 1111 1001,两者相加得:0000 0000 0000 0000 0000 0000 1111 0011,虽有溢出,但溢出的部分全部丢失,因d和f都为char型,故截取低八位,即1111 0011。运算是在内存中进行的,打印是在寄存器中进行。d为无符号,存入寄存器中高位补0;f为有符号,高位补符号位。

unsigned char a = -196;
unsigned char b = 14;
char c = -196;
char d = 14;
printf("%d\n",a+d);
printf("%d\n",c+b);
输出:
74
74

解析:
无符号·char的范围为0 ~ 255,有符号的为-128 ~ 127。因为196溢出,-196的补码为0011 1100(60的原码),14的补码为0000 1110;无论-196为unsigned还是signed,高位都补0(signed-196的符号为0);因为char和unsigned char要转为int和unsigned int类型(低位转高位);-196的补码为0000 0000 0000 0000 0000 0000 0011 1100(32位),14的补码为0000 0000 0000 0000 0000 0000 0000 1110,两者相加得:0000 0000 0000 0000 0000 0000 0100 1010,即74。

unsigned char a = -123;
unsigned char b = 14;
char c = -123;
char d = 14;
printf("%d\n",a+d);
printf("%d\n",b+c);
输出:
147
-109

解析:
-123的补码为1000 0101,转为int型的补码为1111 1111 1111 1111 1111 1111 1000 0101(有符号),或0000 0000 0000 0000 0000 0000 1000 0101(无符号),与14相加得1111 1111 1111 1111 1111 1111 1001 0011(b+c),或0000 0000 0000 0000 0000 0000 1001 0011(a+d)。故a+d的结果为147,b+c的结果为-109。

unsigned int a = -10;
if(a>10)
printf("yes\n");
else
printf("no\n");
输出:
yes

解析:a为无符号数且a为负数,-10的补码为1111 1111 1111 1111 1111 1111 1111 0110(int为32位),转化为10进制数为2^32-10,显然大于10。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值