正数:原码=反码=补码
负数:反码=原码所有位(符号位除外)取反; 补码=反码 + 1
以 char 为例:
值 | 原码 | 反码 | 补码 |
---|---|---|---|
1 | 0000 0001 | 0000 0001 | 0000 0001 |
-1 | 1000 0001 | 1111 1110 | 1111 1111 |
127 | 0111 1111 | 0111 1111 | 0111 1111 |
-127 | 1111 1111 | 1000 0000 | 1000 0001 |
0 | 0000 0000(正 0) | 0000 0000 | 0000 0000 |
-128 | 1000 0000(负 0) | 1111 1111 | 1000 0000 |
现在机器里存储的就是最后的 补码,通过补码就把正、负 0 区分开来了
这样就有个问题需要注意了:
n = -n;
这里 n 不能是最小负数,是的话 n 就会超过它的最大值。
可以通过以下程序看一下最值:
#include <stdio.h>
#include <limits.h>
int main()
{
/* int 型变量的最值,打印标准头文件得出 */
printf("%d\n", INT_MAX);
printf("%d\n", INT_MIN);
printf("%d\n", SCHAR_MAX);
printf("%d\n", SCHAR_MIN);
/* int 型变量的最值,直接计算方式得出 */
printf("%d\n", (int)((unsigned int) ~0 >> 1));
printf("%d\n", -(int)((unsigned int) ~0 >> 1) - 1);
/* 对1的二进制进行取反、存储,打印结果为 -2 */
printf("%d\n", ~1);
/* 对原码取反码、补码,存储补码,打印结果为 -2 */
printf("%d\n", -2);
/* 两者结果相同,因 ~1 正好为 -2 的补码 */
return 0;
}