学习按位取反时,一直不是很理解,为啥对0取反就是-1,对76取反就是-77,网上有说记住x+(~x)=-1就可以了,可还是有点难懂。所以我来解释一波为啥对0取反就是-1?
- 十进制数 0 的十六进制表示为 0000 0000
- 对其~(取反)后得到 1111 1111
- 此时这个值转化为十进制就是255
- 此时 255-256=-1
同理 76 的十六进制为 0100 1100,取反后为1011 0011,转为十进制数为179,179-256= -77
这里其实就是有符号数的转化,在8位的范围内(0~255),最大值就只能到255。
当然,对于16位、32位数也适用,大家可以试一试。
扩展知识点
——无符号数中的负数怎么表示
在无符号的8位数值中,由于不能为负值,所以-1实际上不能以-1的形式存在(很绕但确实是这样的),实际你看到的显示出来的数值为255,这是为啥呢?
例如下面这样:
#include <stdio.h>
typedef unsigned char U8;//8位无符号数,范围0~255
int main(void)
{
U8 u8_num=-1;
print("%d\n",u8_num);
return 0;
}
结果是
255
我们定义了一个8位的无符号数值,所以它的范围是0~255,-1不在这个范围内,所以此时它如何显示?这涉及到负数在计算机中的表示了。
我们知道,在计算机系统中数据都是以补码形式存储的,只不过正数的补码等于反码又等于原码。而负数的补码等于对原码取反加1。
那我们求一下-1的补码(8位数值)
原码:1000 0001,(最高位为符号位,为1代表负数,为0代表正数)
反码:1111 1110,(符号位不变,其他位按位取反)
补码:1111 1111,(反码 + 1)
我们看这个补码是不是很熟悉??
没错,这个-1的补码也就是我们无符号数255的原码和补码;
正数的补码等于其本身
这里就有一个疑问,数值的原码首位不是符号位吗?为啥1111 1111却可以表示为正数255呢?
如果你的变量是8位的带符号的数,那么最高位第7位作为符号位用,最高位为0时表示是正数,为1时表示是负数;而无符号数是相对于有符号数而言的,指的是整个机器字长的全部二进制位均表示数值位,相当于数的绝对值。
也就是说无符号数没有符号位,符号位是有符号数玩的把戏。
在无符号数中,1111 1111是255,但在有符号数中,1111 1111就是-1的补码。
所以我们原本是想在一个无符号数中表示一个有符号数(-1),这是不现实的,但最终计算机妥协了,不过是以无符号数的形式(255)表现出来的有符号数(-1)。
关于补码,下面的介绍可以帮助大家了解更详细一点。本文就说这么多吧。
正数的原码=反码=补码。引进补码的作用是为了让计算机更方便做减法。
例如:按时间12个小时来算,现在的准确时间是4点,有一个表显示的是7点,如果要校准时间,我们可以将时针退7-4=3格,也可以向前拨12-3=9格,计算机做减法就可以使-3转化为+9,这样可以简化计算机的硬件设备去做复杂的减法。
所以补码反码就是为了简化减法而来的,将减号化为负数,再将负数化为补码求加法,跟正数没关系。所以不管是正整数还是正小数,原码,反码,补码都全部相同。1
参考文献:
https://zhidao.baidu.com/question/2208490602456362988.html ↩︎