无符号整数和有符号整数的区别

无符号整数和有符号整数的区别

Posted by Twany on November 9, 2019

无符号整数和有符号整数的区别

在平时我们定义一个整形变量时,方法应该都是这样的:

1
int x = 1;

这样定义的变量默认是有符号的,即区分正负数。

那么无符号整数是什么样的呢?无符号整数顾名思义,只能存储正整数。

程序演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
 
/* 
 * 这个程序演示了有符号整数和无符号整数之间的差别
*/
int main()
{
   int i;           // 有符号整数
   unsigned int j;  // 无符号整数
 
   j = 50000;
 
   i = j;
   cout << i << " " << j;
 
   return 0;
}

c++ 为例,我们定义了一个有符号整数和一个无符号整数,那么程序的输出是什么,第一感觉都应该是:

1
50000 50000

其实正确的输出结果是:

1
-15536 50000

Why

当我们写好了程序,下一步便交由计算机系统去执行代码,即变为低级语言去进行底层操作。

以变量 j 为例,j 变为16位二进制(具体位数根据机器型号,此处以16位例):

1100 0011 0101 0000

机器只能识别 0 1,无法识别正负数,所以聪明的前辈就想到了一种解决方法:用数的第一位作为符号位:0位正数,1位负数。

上述16位二进制的第一位为 1,这就代表它是一个负数,定义的 i 为有符号数,所以我们需要再把二进制数转为十进制有符号数

原码和补码

计算机中数据是以补码形式存放的,用二进制表示。在理解补码前我们先说一下原码:原码就是数的最初形式,如上处的 50000,它的原码就是转换的 1100 0011 0101 0000

原码和补码的具体关系此处不再赘述,我们只需要了解 原码如何转换成 补码即可:

符号位不变,各位取反,末尾加一

比如上述的 1100 0011 0101 0000:

  • 符号位为第一位 1 不变
    • 变为 1100 0011 0101 0000
  • 其余各位取反(1 变 0, 0 变 1 )
    • 变为 1011 1100 1010 1111
  • 末尾加一(1011 1100 1010 1111 + 1)
    • 变为 1011 1100 1011 0000

所以, 1100 0011 0101 0000 的补码就是 1011 1100 1011 0000

去掉最高符号位 1, 将 011 1100 1011 0000 转换为十进制

加上符号 1(负数),即为 -15536,和程序结果相同

总结

转换的步骤其实难在原补码的转换和符号位的考虑

一般情况下我们使用的都是有符号整数,不会出现上述情况,但当涉及到了无符号数,那就要多考虑一步了。