1. 引言

在计算机系统中,数据以二进制形式存储。编程语言如 C、Java 或 Python 中,变量可以以 8 位、16 位、32 位或 64 位的形式存在。我们常会遇到“有符号(signed)”和“无符号(unsigned)”变量的概念。它们决定了变量所能表示的数值范围和符号处理方式。本文将系统地解释它们之间的区别,帮助你理解何时使用哪种类型。


2. 一个简单的例子

我们先以一个“4 位”存储系统为例,来理解不同变量类型的表现形式。

一个 n 位的二进制数可以表示 $ 2^n $ 个不同的值。在 4 位系统中,总共有 $ 2^4 = 16 $ 个可能的值。

如果我们将这些值解释为 无符号数,则其范围为 0 到 $ 2^n -1 $,即 0 到 15。

下图展示了 4 位无符号数的所有可能值:

img_62ff5ea170d23


3. 一补码(One’s Complement)

在“一补码”表示法中,最左边的一位作为符号位

  • 若为 0,表示正数;
  • 若为 1,表示负数。

对于正数,直接将其余位转换为十进制即可。例如:

  • 0101 表示 +5。

对于负数,我们通过将所有位取反(0 变 1,1 变 0)来得到其绝对值。例如:

  • 1011 表示 -4,因为取反后为 0100,即 4。

3.1 一补码的问题

一补码的一个显著问题是:存在两个零

  • 0000 表示 +0;
  • 1111 表示 -0。

这在早期使用一补码的计算机中是一个棘手的问题,因为程序必须同时处理这两种“零”。现代系统中已很少使用一补码,但在某些特定场景(如 TCP 校验和)中仍需注意。


4. 二补码(Two’s Complement)

二补码是对一补码的改进。其关键区别在于:

  • 负数的计算方式是:先取反(一补码),再加 1。

例如:

  • 1010 是负数;
  • 取反得 0101
  • 加 1 得 0110,即 6 → 所以 1010 表示 -6。

4.1 正数的表示

与一补码相同,正数的符号位为 0,其余位直接转换为十进制即可。

4.2 负数的表示

负数的符号位为 1,求值方法是:

  1. 取反所有位;
  2. 加 1;
  3. 得到绝对值。

4.3 负数范围

在 n 位二补码系统中,负数范围是:

  • $ -1 $ 到 $ -2^{n-1} $

在 4 位系统中,范围是 -1 到 -8。

这比一补码多了一个负数(-8),而且只有一个 0,避免了“+0 和 -0”共存的问题。


5. 总结对比

下表总结了无符号、一补码和二补码的表示范围和特点:

5.1 无符号数(Unsigned)

位数 范围 二进制表示
8 0 ~ 255 00000000 ~ 11111111
16 0 ~ 65535 00000000 00000000 ~ 11111111 11111111
32 0 ~ 4294967295 四组 11111111
n 0 ~ $ 2^n -1 $ -

特点:只能表示非负数,范围最大。


5.2 一补码(One's Complement)

位数 范围 二进制表示
8 -127 ~ +127(含 +0 和 -0) 10000000 ~ 1111111100000000 ~ 01111111
16 -32767 ~ +32767 -
32 -2147483647 ~ +2147483647 -
n $ -(2^{n-1}-1) $ ~ $ +(2^{n-1}-1) $ -

缺点:存在两个零,易导致判断错误。


5.3 二补码(Two's Complement)

位数 范围 二进制表示
8 -128 ~ +127 10000000 ~ 1111111100000000 ~ 01111111
16 -32768 ~ +32767 -
32 -2147483648 ~ +2147483647 -
n $ -2^{n-1} $ ~ $ +(2^{n-1}-1) $ -

优点:只有一个零,广泛用于现代计算机系统。


6. 结论

  • 无符号变量不能表示负数,但表示范围更大。
  • 一补码存在两个零(+0 和 -0),容易造成判断错误,现代已很少使用。
  • 二补码是目前最常用的有符号整数表示方式,只有一个零,且负数范围比正数大一位。
  • 在实际开发中,如 C/C++、Java 等语言中默认使用二补码表示有符号整数。

📌 踩坑提醒:在进行位操作或跨语言数据传输时,注意不同语言对有符号/无符号的默认处理方式,避免出现数值溢出或符号错误。例如 Java 中没有无符号类型,处理无符号数据时需手动转换。


原始标题:What Is the Difference Between Signed and Unsigned Variables?