附:C代码在线调试工具
我们都知道正数在计算机中是转化成其二进制存储的,那么负数呢?
计算机中,负数统一采用的补码形式存储。所以变量被赋值负数后,本质存的就是补码,不用再手动转换成补码。
计算机中,我们最快看到负数补码
的方式,可参考以下代码:
int num = -10;
unsigned int numVer = num;
printf("0x%x\n", numVer);
最快得到负数补码
的方式,输出字符串bigOrder里按大端序输出对应补码,接上面代码:
int modVal = 0;
char bigOrder[9] = "00000000"; // 默认初始为0
char *p1 = &bigOrder[7]; // 从末尾开始放
while (num > 0) { // 若num为0,则转换完成
modVal = num % 16; // 按正数转换成HEX表达
if (modVal >= 10) {
*p1 = (modVal - 10) + 'A';
} else {
*p1 = modVal + '0';
}
p1--;
num /= 16;
}
printf("%s\n", bigOrder);
什么是补码呢?
正数的补码就是该正数本身,负数的补码需要转化,人工转化规则如下:
简单来说,就是负数的补码为其绝对值取反后加1
所得的结果。
-1 , -2 作为有符号数其存储在内存的二进制到底为多少?
负数以补码形式储存,而非其本身二进制本身,即符号位+绝对值
。比如,char
类型的-1
在计算机存储的不是1000 0001
;而是1111 1111
,即0xff
。
以char类型举例,详细说明下其转换过程。
char
类型默认为signed char
, 其取值范围是 -128 ~ 127
,即-2e7 ~ 2e7-1
, 用最高位表示其符号,0
表示正数,1
表示负数。
举例:-1 取绝对值0000 0001 -> 取反1111 1110 ->加1得到 1111 1111 0xff
举例:-2 取绝对值0000 0010 -> 取反1111 1101 ->加1得到 1111 1110 0xfe
注意:char类型的0 没有+0 和 -0 的区分,按上述操作,不管正负结果都是 0000 0000
用以下代码即可验证:
signed char x0 = 0xff; // -1
signed char x1 = 0xfe; // -2
signed char x3 = 0;
signed char x4 = -1;
printf("%d\n", x0);
printf("%d\n", x1);
printf("0x%x\n", x3);
printf("0x%x\n", x4);
8位有符号数补码排布方式:
8位整型进制表达范围:0x00-0xff,可见补码在比较负数大小时,计算机中依然可以按数值大小去比较。
以int类型为例,分析有符号数据类型的最小范围数值表示。
int
为4字节32位,其中首位用0表示正数,用1表示为负数,数值范围[-2^31, 2^31-1]
。
最大正数为:0x7fff ffff
(7的二进制为0111,f二进制为1111)
最大负数(-1)实际存储的补码为:0xffff ffff
最小负数(-2147483648)实际存储的补码为:0x8000 0000
(8的二进制为1000)
负数为源码取反码再取补码,以-1为例,过程如下:
1. 写原码: 10000000 00000000 00000000 00000001
2. 得反码: 11111111 11111111 11111111 11111110
3. 得补码: 11111111 11111111 11111111 11111111
重要重要,下面这个知识点最常出问题!!!
最小负数没有原码和反码
表示,最高位为1,其余位为0,就是最小负数。如-2147483648:
1. 原码:NA
2. 反码:NA
3. 补码:10000000 00000000 00000000 00000000
也可以用另一种方式求补码,可以不用考虑以上问题。过程是:先得绝对值,对其取反,再加1可得补码:
1. 绝对值: 10000000 00000000 00000000 00000000 (2^31 = 2147483648)
2. 取反: 01111111 11111111 11111111 11111111
3. 加1得补码:10000000 00000000 00000000 00000000
只有最小范围这个情况较特殊,结果变换后还是自己。
那为什么对应类型的最小负数无原码和反码表示呢?
-2147483648
的绝对值占用了符号位,导致必须往前加一位符号位才能表示,而此时已占用33位bit。-2147483648
的原码。1 00000...
和 0 00000...
是两种类型的0,第一个是符号位为1的0,第二个是符号位为0的0,刚好拿来表达最小负整数和最小正整数。重要小结
INT_MIN
的补码为1000 0000 0000 0000 0000 0000 0000 0000
,即0x8000 0000
INT_MIN + 1
的补码为1000 0000 0000 0000 0000 0000 0000 0001
,即0x8000 0001
-1
的补码为1111 1111 1111 1111 1111 1111 1111 1111
,即0xffff ffff
INT_MIN -> 100000...
,这样递增映射原码、反码、补码:
各自优缺点: