原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值
例如:
1的8位二进制表示:
0000 0001
-1的8位二进制表示:
1000 0001
所以8位二进制能够表示的取值范围(其实不然)[-127,127] 即:
1111 1111
0111 1111
原码是人脑最容易理解和计算的表示方式.
正数的反码是其原码
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
例如:
1的8位二进制反码表示:
0000 0001
-1的8位二进制反码表示:
1111 1110
正数的补码就是其原码
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1,即在反码的基础上+1
例如:
1的8位二进制补码表示:
0000 0001
-1的8位二进制反码表示:
1111 1110
-1的8位二进制补码(在反码的基础上+1)表示:
1111 1111
正数的补码就是其原码
对于一个负数的补码求原码就是原码转换补码的逆过程
例如:
-1的8位二进制补码表示:
1111 1111
-1的8位二进制反码(在补码的基础上-1)表示:
1111 1110
-1的8位二进制原码(符号位不变,按位取反。或者先取反后+1)表示:
1000 0001
为什么要使用反码、补码?使用原码不是更易于理解吗?
使用8位原码进行减法运算
例如计算1-1:
1-1 == 1+(-1)
1的原码:0000 0001
-1的原码:1000 0001
相加:1000 0010
十进制:-2
上面的例子运算结果显然不对
为了解决原码做减法的问题, 出现了反码:
使用8位反码进行减法运算
例如计算1-1:
1-1 == 1+(-1)
1的反码:0000 0001
-1的反码:1111 1110
相加:1111 1111
原码:1000 0000
十进制:-0
发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在0这个特殊的数值上 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的 而且会有[0000 0000]和[1000 0000]两个编码表示0
于是补码的出现, 解决了0的符号以及两个编码的问题:
使用8位补码进行减法运算
例如计算1-1:
1-1 == 1+(-1)
1的补码:0000 0001
-1的补码:1111 1111
相加:0000 0000
原码:0000 0000
十进制:0
这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了,而且可以用[1000 0000]表示-128
例如计算-1-127:
-1-127 == (-1) + (-127)
-1-127
-1补码1111 1111
-127补码1000 0001
相加:1000 0000
-1-127的结果应该是-128, 在用补码运算的结果中, 补码1000 0000 就是-128 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示
使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127] 而使用补码表示的范围为[-128, 127]
我们知道8位二进制能够表达的取值范围是[-128, 127]
那么我们在写代码时,如果赋值时给出了能够表达的取值范围以外的数,会发生什么?
例如:
char c1 = 129;
cout << (int)c1 << endl;
char c2 = 270;
cout << (int)c2 << endl;
结果:
-127
14
首先在程序中这种行为是坚决不允许的,而且出现这样的问题也难查
我们先看看为什么是-127、14
我们先不考虑目标变量是几字节的,
先看看129、270的原码:
129: 0000 1000 0001
270: 0001 0000 1110
我们知道正数的补码就是原码,
所以129、270的补码是:
129: 0000 1000 0001
270: 0001 0000 1110
那么对于一个单字节变量来说,我们对129、270的补码取8位
c1: 1000 0001
c2: 0000 1110
而这是补码,按照上面的运算法则取8位转换成原码:
c1: 1111 1111
c2: 0000 1110
所以我们推导出结果是:
-127
14
还有一个问题我们都遇见过,就是将一个负数赋值给一个无符号整型
例如:
unsigned int unT2 = -1;
最终unT2的值是多少我们不讨论了,很简单了。
例如通过一个32位整型代表角色当前状态
typedef enum State
{
E_INIT = 0,
E_DEAD = 1 << 0,
E_RIDE = 1 << 1,
E_FLY = 1 << 2,
}RoleState;
class Role
{
public:
Role()
{
m_nState = RoleState::E_INIT;
}
void AddState(RoleState ms)
{
m_nState |= (int)ms;
}
void RemoveState(RoleState ms)
{
m_nState &= ~((int)ms);
}
bool IsDead()
{
return m_nState & (int)(RoleState::E_DEAD);
}
void PrintState()
{
cout << "Role State " << m_nState << endl;
}
private:
int m_nState;
};
{
Role objRole;
cout << "Init State" << endl;
objRole.PrintState();
cout << "Add Ride Flag" << endl;
objRole.AddState(RoleState::E_RIDE);
objRole.PrintState();
cout << "Role is dead? " << objRole.IsDead() << endl;
cout << "Add Dead Flag" << endl;
objRole.AddState(RoleState::E_DEAD);
objRole.PrintState();
cout << "Role is dead? " << objRole.IsDead() << endl;
cout << "Remove Dead Flag" << endl;
objRole.RemoveState(RoleState::E_DEAD);
objRole.PrintState();
}
输出:
Init State
Role State 0
Add Ride Flag
Role State 2
Role is dead? 0
Add Dead Flag
Role State 3
Role is dead? 1
Remove Dead Flag
Role State 2
参考文章:https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html