原码和补码在系统中运行的应用
- 1. 原码、反码与补码
- 2. 加法运算 (10 + (-12))
- 3. 减法运算 (10 - (-12))
- 4. 输出时的转换过程
- 总结
在学习C++的时候遇到了数据过大导致数据溢出的问题,让我对数的存储存在疑惑。下面就详细讲讲整数型数据的加减法运行。
首先这个属于整数型数据存储在内存中的操作,此时数按照二进制的形式存储在内存中。为了统一加减法运算,计算机使用补码来存储整数。
1. 原码、反码与补码
对于一个有符号整数(假设为8位),其存储转换关系如下:
| 数值 | 原码 (Sign-Magnitude) | 反码 (Ones‘ Complement) | 补码 (Two’s Complement) |
|---|---|---|---|
| +10 | 0000 1010 | 0000 1010 | 0000 1010 |
| -12 | 1000 1100 | 1111 0011 | 1111 0100 |
转换规则:
- 正数:原码、反码、补码三者相同。
- 负数:
- 原码:符号位为1,其余位表示绝对值。
- 反码:符号位不变,原码的数值位按位取反。
- 补码:反码 + 1。
2. 加法运算 (10 + (-12))
系统使用补码进行加法,直接对存储的二进制位相加。
补码 10: 0000 1010 + 补码 -12: 1111 0100 ---------------------- 1111 1110 (补码结果)结果分析:1111 1110是一个负数的补码。但如果不需要输出就会这样保持在内存中。
3. 减法运算 (10 - (-12))
系统将减法转化为加法:A - B = A + (-B)。其中-B即对B的补码再求一次补码(即得到-B的补码)。
已知:
- 被减数 A = 10, 补码为
0000 1010 - 减数 B = -12, 补码为
1111 0100
步骤:
- 求
-B: 因为 B = -12, 所以 -B = 12。 - 求
12的补码(正数补码即原码):0000 1100。 - 执行加法:
10的补码 + 12的补码。
补码 10: 0000 1010 + 补码 12: 0000 1100 ---------------------- 0001 0110 (补码结果)结果分析:0001 0110是正数补码,直接转换为十进制为 22。结果正确:10 - (-12) = 22。
4. 输出时的转换过程
当程序需要输出一个整数(例如通过printf)时,运行库(如 libc)需要将内存中的补码还原为人类可读的十进制形式,其实这里又是一个补码的过程。
以补码1111 1110(即 -2) 的输出为例:
- 读取补码:
1111 1110(符号位为1,是负数)。 - 补码转一次补码:
- 补码
1111 1110 - 取反:
0000 0001 - 加1得原码的绝对值:
0000 0010
- 补码
- 原码数值位
000 0010对应十进制 2。 - 加上负号,输出
-2。
总结
通过使用补码表示法,计算机系统统一了加法和减法运算,只需一个加法器即可完成。理解原码、反码、补码之间的转换关系,是理解整数在计算机中如何存储、运算和输出的关键,也能帮助我们更好地调试数据溢出等问题。