Appearance
第2章 数据编码
🎯 本章学习目标
学完本章,你将能够:
- 理解计算机采用二进制存储数据的原因,以及符号位的含义
- 区分机器数与真值的概念,避免把符号位当数值位计算
- 掌握原码、反码、补码的定义与相互转换方法
- 熟练手算给定十进制数的 8 位/16 位补码
- 熟练已知补码反求真值(十进制数)
- 理解补码的三大优势:减法变加法、零的表示唯一、多一个最小负数
- 记住 n 位补码的表示范围:-2^(n-1) ~ 2^(n-1)-1
- 掌握溢出的判断方法:同号相加结果变号则溢出
- 理解 signed 与 unsigned 的区别,以及 char 类型的符号性问题
- 了解用 C++ 的 bitset 验证和输出二进制编码(拓展内容)
🗺️ 本章知识图谱
数据编码(原码、反码、补码)
├── 基本概念
│ ├── 计算机内部是二进制
│ ├── 机器数 vs 真值
│ └── 符号位(0正1负)
├── 原码
│ ├── 定义:符号位 + 绝对值
│ ├── 问题一:0有两种表示(+0和-0)
│ └── 问题二:加减法运算复杂
├── 反码
│ ├── 正数:同原码
│ ├── 负数:符号位不变,数值位取反
│ └── 地位:原码转补码的中间桥梁
├── 补码 ⭐(核心)
│ ├── 正数:三码合一
│ ├── 负数:反码 + 1
│ ├── 三大优势
│ │ ├── 减法变加法(统一用加法器)
│ │ ├── 零的表示唯一
│ │ └── 多一个最小负数(-128)
│ ├── 表示范围:-2^(n-1) ~ 2^(n-1)-1
│ ├── 快速求法:从右数第一个1左边取反
│ └── 已知补码求真值:再求补得原码
├── 溢出判断
│ ├── 同号相加结果变号 → 溢出
│ └── 异号相加永远不溢出
└── C++ 中的编码
├── signed vs unsigned
├── char 的符号性由平台决定
└── bitset 查看二进制(拓展)一、为什么需要数据编码?
1.1 计算机只认识 0 和 1
计算机的硬件电路只有"高电平"和"低电平"两种状态,因此所有数据在计算机内部都以二进制存储。数字 5 在 8 位二进制中写作 0000 0101,这很好理解——可负数怎么办?数字前面可没有"负号键"。
科学家们想到一个办法:用最高位充当符号位。
- 最高位为 0,表示正数
- 最高位为 1,表示负数
由此引出两个概念:
| 概念 | 含义 | 举例 |
|---|---|---|
| 机器数 | 一个数在计算机中的二进制表示形式(带符号位) | -5 的机器数是 1000 0101 |
| 真值 | 机器数真正表示的十进制数值(要考虑符号位) | 1000 0101 的真值是 -5,不是 133 |
⚠️ 易错点: 机器数的最高位是符号位,不能当普通数值位算!
1000 0101直接按二进制算是 133,但它的真值是 -5。考试中经常在这里挖坑。
1.2 三种编码方案
为了让负数既能被表示、又能正确参与运算,人们先后设计了三种编码:
- 原码:最直观,符号位 + 数值的绝对值
- 反码:原码与补码之间的"桥梁"
- 补码:现代计算机实际使用的编码 🎯
下面逐一拆解。
二、原码:最直观的表示法
2.1 定义
原码:最高位为符号位(0 正 1 负),其余位表示数值绝对值的二进制。
以 8 位为例:
+5 的原码: 0 000 0101
↑
符号位0,表示正数
-5 的原码: 1 000 0101
↑
符号位1,表示负数2.2 原码的两个致命问题
问题一:0 有两个原码
+0 的原码:0000 0000
-0 的原码:1000 0000数学上 0 不分正负,但原码里却有两个"0",既浪费编码又给判断带来麻烦。
问题二:直接做加减法会出错
用原码计算 1 + (-1):
0000 0001 (+1 的原码)
+ 1000 0001 (-1 的原码)
-----------
1000 0010 = -2 ❌ 结果居然是 -2!符号位参与运算导致结果完全错误。若要让原码正确做减法,硬件需要额外判断符号、比较绝对值大小,电路设计十分复杂。
🔥 高频考点: 原码的优点是人眼直观、转换方便;缺点是 0 有两种表示、加减法运算规则复杂。8 位原码的表示范围是 -127 ~ +127(注意没有 -128)。
三、反码:承上启下的过渡编码
3.1 定义
- 正数的反码 = 原码(不变)
- 负数的反码:符号位保持 1 不变,其余数值位按位取反(0 变 1,1 变 0)
以 8 位 -5 为例:
-5 的原码: 1 000 0101
↓ 数值位逐位取反
-5 的反码: 1 111 1010正数 +5 的反码则与原码完全相同:0000 0101。
3.2 反码的小练习
| 十进制 | 原码(8位) | 反码(8位) |
|---|---|---|
| +7 | 0000 0111 | 0000 0111 |
| -7 | 1000 0111 | 1111 1000 |
| +1 | 0000 0001 | 0000 0001 |
| -1 | 1000 0001 | 1111 1110 |
反码同样存在 +0(0000 0000)和 -0(1111 1111)两个零,而且用反码做 1 + (-1):
0000 0001
+ 1111 1110
-----------
1111 1111 = -0 (结果是个"负零",需要额外处理)⚠️ 易错点: 反码在现代计算机中并不直接用于存储和运算,它只是原码转补码过程中的中间产物。考试若问"计算机中整数实际采用什么编码",答案永远是补码。
四、补码:计算机真正使用的编码 ⭐⭐⭐⭐⭐
4.1 定义
- 正数的补码 = 原码(三码合一)
- 负数的补码 = 反码 + 1(即:符号位不变,数值位取反后再加 1)
以 8 位 -5 为例完整走一遍:
第1步 写原码: 1 000 0101 (-5)
第2步 求反码: 1 111 1010 (数值位取反)
第3步 反码+1: 1 111 1011 (-5 的补码)✅4.2 补码的三大优势
优势一:加减法统一,减法变加法
用补码计算 1 + (-1):
0000 0001 (+1 的补码)
+ 1111 1111 (-1 的补码)
-----------
1 0000 0000 (最高位产生进位,超出8位直接丢弃)
= 0000 0000 = 0 ✅ 完美!CPU 只需一个加法器就能同时处理加法和减法,硬件大大简化。
优势二:0 的表示唯一
-0 的补码怎么求?反码 1111 1111 加 1 得到 1 0000 0000,进位丢弃后就是 0000 0000,和 +0 完全相同!
优势三:多出一个编码 -128
既然 1000 0000 不再浪费在"-0"身上,就用它表示补码中最小的负数 -128(8 位下 -128 没有对应的原码和反码,是补码"专属"的数)。
🔥 高频考点: n 位补码的表示范围是 -2ⁿ⁻¹ ~ 2ⁿ⁻¹ - 1。
- 8 位补码:-128 ~ 127
- 16 位补码:-32768 ~ 32767
- 32 位补码(常见的 int):约 -21 亿 ~ 21 亿
负数比正数多一个,这是补码独有的特点!
4.3 生活中的补码思想:调钟表
为什么"取反加一"这么神奇?可以用钟表理解:钟面一圈 12 个小时(模为 12),从 8 点调到 6 点,既可以逆时针拨 2 小时(8 - 2 = 6),也可以顺时针拨 10 小时(8 + 10 = 18,18 mod 12 = 6)。
也就是说,在模 12 的系统里,-2 和 +10 等价。8 位二进制的模是 2⁸ = 256,所以 -5 和 +251 等价——而 251 的二进制正是 1111 1011,这就是 -5 的补码!
4.4 负数补码的快速求法
除了"取反加一",还有一个更快的手算技巧:
从右往左找到第一个 1,这个 1 及其右边的 0 保持不变,左边的所有数值位逐位取反,符号位始终为 1。
例:求 -5 的补码,原码数值位 000 0101:
1 000 0101
↑ 从右数第一个1
1 111 1011 ← 该1及其右侧不变,左侧数值位取反结果与"取反加一"完全一致。
五、三种编码对比大表
5.1 8 位编码对照表
| 十进制真值 | 原码 | 反码 | 补码 |
|---|---|---|---|
| +7 | 0000 0111 | 0000 0111 | 0000 0111 |
| -7 | 1000 0111 | 1111 1000 | 1111 1001 |
| +5 | 0000 0101 | 0000 0101 | 0000 0101 |
| -5 | 1000 0101 | 1111 1010 | 1111 1011 |
| +1 | 0000 0001 | 0000 0001 | 0000 0001 |
| -1 | 1000 0001 | 1111 1110 | 1111 1111 |
| +0 | 0000 0000 | 0000 0000 | 0000 0000 |
| -0 | 1000 0000 | 1111 1111 | 0000 0000(进位丢弃) |
| -128 | ❌ 无法表示 | ❌ 无法表示 | 1000 0000(补码专属) |
5.2 16 位编码示例
| 十进制真值 | 原码 | 反码 | 补码 |
|---|---|---|---|
| +5 | 0000 0000 0000 0101 | 同原码 | 同原码 |
| -5 | 1000 0000 0000 0101 | 1111 1111 1111 1010 | 1111 1111 1111 1011 |
| +32767 | 0111 1111 1111 1111 | 同原码 | 同原码 |
| -32768 | ❌ | ❌ | 1000 0000 0000 0000 |
🔥 记忆口诀: 正数"三码合一";负数"原码看绝对值,反码数值位取反,补码反码再加一"。
六、已知补码,如何求原码和真值?
考试常反过来考:给你一个补码,问它表示的十进制数是多少。
6.1 正数:补码即原码
符号位为 0,直接把数值位转成十进制即可。如补码 0000 0111 → 真值 +7。
6.2 负数:两种方法
方法一:逆运算(补码减 1 得反码,再取反得原码)
补码 1111 1011
减1 → 1111 1010(反码)
数值位取反 → 1000 0101(原码)= -5方法二:对补码再求一次补(推荐!)
补码的补码就是原码。 对负数补码的数值位再次"取反加 1",符号位不变,直接得到原码。
补码 1 111 1011
数值位取反 1 000 0100
加1 1 000 0101 = -5 ✅6.3 特殊值
- 补码
1000 0000的真值是 -128(不要按原码规则算成 -0!) - 补码
1111 1111的真值是 -1
七、典型考题类型
7.1 题型一:给定十进制数,求补码
例: 求 -13 的 8 位补码。
13 = 8+4+1 = 0000 1101
原码:1000 1101
反码:1111 0010
补码:1111 0011 ✅7.2 题型二:补码表示范围
例: 8 位补码能表示多少个不同的整数?
答:-128 ~ 127 共 256 个,正好把 2⁸ 个编码全部用完,没有浪费。
7.3 题型三:溢出判断
🔥 高频考点: 两个同号数相加,若结果符号与它们相反,则发生溢出;异号相加永远不会溢出。
例: 8 位补码下计算 127 + 1:
0111 1111 (+127)
+ 0000 0001 (+1)
-----------
1000 0000 (符号位变成1!按补码解释为 -128)两个正数相加竟得出负数——这就是溢出。同理 -128 - 1 也会溢出得到 +127。
八、C++ 中的编码:signed、unsigned 与 char
📚 拓展 · 超纲:本节用到的
bitset属于 C++ 标准库容器,不在三级考纲范围内。这里仅把它当作"把内存中的二进制打出来看"的演示工具,帮助理解补码;考试不会考查 bitset 的用法,读者了解即可。
C++ 中的整数类型在主流编译器下一律采用补码存储。我们可以用 C++11 的 bitset 把内存中的二进制"打"出来验证。
8.1 打印二进制,验证原反补
cpp
#include <iostream>
#include <bitset> // bitset 所在头文件
using namespace std;
int main() {
// 计算机中整数直接以补码存储,bitset<8> 取低8位显示
int a = 5;
int b = -5;
cout << "+5 在内存中的8位二进制: " << bitset<8>(a) << endl;
// 输出:00000101(正数三码合一)
cout << "-5 在内存中的8位二进制: " << bitset<8>(b) << endl;
// 输出:11111011(正是 -5 的补码)
// 手工演示原码 -> 反码 -> 补码的推导过程
// 注意:`0b` 前缀是 C++14 引入的特性,
// 部分老旧环境(甚至 C++98)下 `0b` 写法编译不通过。
int yuanma = 0b10000101; // -5 的原码:符号位1 + 数值5
int fanma = 0b11111010; // -5 的反码:符号位不变,数值位取反
int buma = 0b11111011; // -5 的补码:反码 + 1
cout << "原码: " << bitset<8>(yuanma) << endl; // 10000101
cout << "反码: " << bitset<8>(fanma) << endl; // 11111010
cout << "补码: " << bitset<8>(buma) << endl; // 11111011
return 0;
}8.2 验证补码"减法变加法"
cpp
#include <iostream>
#include <bitset>
using namespace std;
int main() {
// 1 + (-1):补码相加,进位丢弃后结果为 0
int x = 1, y = -1;
cout << x << " + (" << y << ") = " << x + y << endl; // 0
cout << bitset<8>(x) << " + " << bitset<8>(y)
<< " = " << bitset<8>(x + y) << endl;
// 00000001 + 11111111 = 00000000(第9位的进位被丢弃)
// 5 - 3 在硬件中就是 5 + (-3)
cout << "5 + (-3) = " << 5 + (-3) << endl; // 2
return 0;
}8.3 signed 与 unsigned:同一串 0/1,两种解读
1111 1111 这 8 位,按有符号补码解释是 -1,按无符号解释是 255。类型决定了编码的含义!
cpp
#include <iostream>
#include <climits>
using namespace std;
int main() {
// 同样的 8 位二进制 11111111
signed char sc = (signed char)255; // 有符号:按补码解释
unsigned char uc = 255; // 无符号:全部是数值位
cout << "signed char 解释 11111111: " << (int)sc << endl; // -1
cout << "unsigned char 解释 11111111: " << (int)uc << endl; // 255
// 溢出演示:127 + 1(主流编译器下得到 -128,属于未定义/实现相关行为,考试按补码规则推断)
// 注意:有符号整数溢出是未定义行为(UB),不同编译器/平台结果可能不同!
// 以下代码仅为演示"在主流编译器下观察到补码回绕现象",不属于可移植代码。
signed char c = 127;
c = c + 1;
cout << "signed char: 127 + 1 = " << (int)c << endl; // -128,溢出!
// char 的符号性由编译器/平台决定,移植代码时要小心
cout << "当前平台 char 范围: " << CHAR_MIN << " ~ " << CHAR_MAX << endl;
cout << "signed char 范围: " << SCHAR_MIN << " ~ " << SCHAR_MAX << endl; // -128 ~ 127
cout << "unsigned char 范围: 0 ~ " << UCHAR_MAX << endl; // 0 ~ 255
return 0;
}⚠️ 易错点:
char到底是有符号还是无符号,由编译器和平台决定(x86 上的 GCC 默认为有符号);而signed char一定是 -128~127,unsigned char一定是 0~255。三级考试中常考"同样的位模式在不同类型下的值"。
九、📝 实战练习
以下 8 道题覆盖数据编码的核心考点。建议先独立完成,再对照解析查漏补缺。
练习题 1(单选题)
题目: 十进制数 -13 的 8 位二进制补码是( )
A. 1000 1101 B. 1111 0010 C. 1111 0011 D. 0111 0011
🔑 点击查看答案与解析
答案: C
解析:
13 = 8 + 4 + 1 = 0000 1101
-13 原码:1000 1101(符号位为1)
数值位取反:1111 0010(反码)
反码 +1: 1111 0011(补码)✅- A 是 -13 的原码,B 是 -13 的反码,都是经典干扰项;
- D 符号位为 0,表示正数,直接排除。
选 C。
练习题 2(单选题)
题目: 8 位二进制补码 1011 0110 表示的十进制真值是( )
A. -74 B. -54 C. 74 D. 182
🔑 点击查看答案与解析
答案: A
解析: 符号位为 1,是负数补码,需要"再求一次补"得到原码:
补码: 1 011 0110
数值位取反:1 100 1001
加1: 1 100 1010 ← 原码数值位 100 1010 = 64 + 8 + 2 = 74,加上符号位,真值为 -74。
注意:若把
1011 0110误当作原码直接读,会得到 -54(即选项 B),这是最容易掉的坑!务必先看清题目问的是原码还是补码。
选 A。
练习题 3(单选题)
题目: 下列关于 8 位二进制编码的说法,正确的有( )
① 8 位补码能表示的整数范围是 -128 ~ 127 ② 补码中 0 有 0000 0000 和 1111 1111 两种表示 ③ 在 8 位补码下计算 127 + 1,结果为 -128,发生了溢出 ④ C++ 中 char 类型在所有平台上都一定是有符号的
A. ①② B. ①③ C. ②④ D. ①③④
🔑 点击查看答案与解析
答案: B
解析:
- ① 正确 ✅:n 位补码范围 -2ⁿ⁻¹ ~ 2ⁿ⁻¹-1,8 位即 -128 ~ 127。
- ② 错误 ❌:补码最大的优点就是 0 的表示唯一(
0000 0000);1111 1111是 -1 的补码。有两个 0 的是原码和反码。 - ③ 正确 ✅:
0111 1111 + 0000 0001 = 1000 0000,两个正数相加得出负数(-128),符合同号相加结果变号的溢出判定规则。 - ④ 错误 ❌:
char的符号性由编译器/平台决定,并不保证所有平台都有符号;想明确范围应使用signed char或unsigned char。
选 B(①③)。
练习题 4(填空题)
题目:
(1) 8 位补码能表示的最小整数是 ______,最大整数是 ______,共能表示 ______ 个不同的整数。 (2) 16 位补码能表示的整数范围是 ______ ~ ______。 (3) 补码 1000 0000(8位)的真值是 ______。
🔑 点击查看答案与解析
答案: (1) -128、127、256 (2) -32768 ~ 32767 (3) -128
解析:
- (1) n 位补码的范围是 -2^(n-1) ~ 2^(n-1)-1。8 位即 -2^7 ~ 2^7-1 = -128 ~ 127。总个数 = 2^8 = 256 个(128 个负数 + 1 个零 + 127 个正数 = 256)。
- (2) 16 位补码:-2^15 ~ 2^15-1 = -32768 ~ 32767。
- (3)
1000 0000是补码中最小负数 -128 的编码,它没有对应的原码和反码,是补码"专属"的数。千万不要按原码理解成 -0!
🔥 记忆口诀:n 位补码,"负半边"比"正半边"多一个——因为 0 占了正半边的一个位置,而负半边没有正零的对应物。
练习题 5(判断题)
题目: 判断下列说法是否正确,正确打"√",错误打"×"。
(1) 正数的原码、反码、补码完全相同。( ) (2) 8 位原码能表示的范围是 -128 ~ 127。( ) (3) 补码中 0 的表示是唯一的。( ) (4) 两个负数相加,结果符号位为 0,说明发生了溢出。( ) (5) C++ 中 char 类型在所有平台上都是有符号的。( ) (6) -1 的 8 位补码是 1111 1111。( )
🔑 点击查看答案与解析
答案: (1) √ (2) × (3) √ (4) √ (5) × (6) √
解析:
- (1) √:正数"三码合一",这是基础结论。
- (2) ×:-128 ~ 127 是补码的范围。8 位原码的范围是 -127 ~ 127(-0 浪费了一个编码)。
- (3) √:补码最大的优点之一就是零的表示唯一(
0000 0000)。 - (4) √:两个负数相加应该还是负数(符号位为 1),如果符号位变成 0,说明发生了负溢出(下溢)。
- (5) ×:char 的符号性由编译器和平台决定,移植代码时要注意。
- (6) √:-1 的原码
1000 0001→ 反码1111 1110→ 补码1111 1111。也可以用公式验证:全 1 的补码 = -1。
练习题 6(单选题)
题目: 16 位二进制补码 1111 1111 1111 1100 表示的十进制数是( )
A. -4 B. -3 C. 65532 D. -12
🔑 点击查看答案与解析
答案: A
解析: 符号位为 1,是负数。对补码的数值位"再求补"得到原码:
补码: 1 111 1111 1111 1100
数值位取反:1 000 0000 0000 0011
加1: 1 000 0000 0000 0100 ← 原码数值位 000 0000 0000 0100 = 4,加上符号位,真值为 -4。
💡 快速技巧:也可以用"从右往左找第一个 1"的方法。补码
...11111100,从右数第一个 1 在第 2 位(从 0 开始数),该 1 右侧不变(都是 0),左侧数值位全部取反 →...00000100,即 4,所以真值是 -4。
⚠️ 易错提醒:选项 C(65532)是把它当 unsigned 解读的结果。题目没说无符号,默认按有符号补码解读。
练习题 7(单选题)
题目: 在 8 位下,同一二进制 1111 1111 按 signed char 和 unsigned char 解读,值分别是( )
A. -1 和 255 B. -127 和 127 C. 255 和 -1 D. -1 和 127
🔑 点击查看答案与解析
答案: A
解析:
- signed char(有符号字符):按补码解释,最高位是符号位。
1111 1111符号位为 1,是负数。对数值位再求补 →000 0001= 1,所以真值是 -1。 - unsigned char(无符号字符):所有位都是数值位,没有符号位。
1111 1111= 128+64+32+16+8+4+2+1 = 255。
同一串 0/1,类型不同,解读完全不同!选 A。
🍎 生活比喻:同样是一张写着"110"的纸条,在警察局是报警电话,在医院是急救中心,在学校可能是学号。上下文(类型)决定了含义。
练习题 8(程序阅读题)
题目: 阅读以下 C++ 程序,输出结果是( )
cpp
#include <iostream>
using namespace std;
int main() {
signed char c = 127;
c = c + 1;
cout << (int)c << endl;
return 0;
}(注:主流编译器下,signed char 溢出按补码回绕处理)
A. 128 B. -128 C. 0 D. -1
🔑 点击查看答案与解析
答案: B
解析:
signed char 的范围是 -128 ~ 127。127 已经是最大值,再加 1 就溢出了。
用补码手算:
127 = 0111 1111
+ 1 = 0000 0001
-----------------
1000 0000 ← 符号位变成了 11000 0000 按 8 位补码解释就是 -128(补码的最小负数)。
两个正数相加结果变成了负数——这就是典型的正溢出(上溢)。
选 B。
⚠️ 注意:严格来说,有符号整数溢出在 C++ 标准中是"未定义行为"(UB),不同编译器结果可能不同。但在 GESP 考试中,通常按"补码回绕"的规则来考,即 127+1 = -128。
十、📊 考点总结表
| 考点 | 重要程度 | 出题形式 | 易错点 |
|---|---|---|---|
| 机器数与真值、符号位 | ⭐⭐⭐ | 选择/判断 | 把符号位当数值位直接计算;混淆机器数和真值 |
| 原码表示法 | ⭐⭐⭐ | 选择 | 忘记 0 有两个原码;范围记成 -128~127 |
| 反码表示法 | ⭐⭐ | 选择/填空 | 负数反码符号位也跟着取反 |
| 补码表示法(求补码) | ⭐⭐⭐⭐⭐ | 选择/程序阅读 | 忘记"+1";符号位参与取反 |
| 补码的优点与表示范围 | ⭐⭐⭐⭐⭐ | 选择/判断 | 范围记成 -127~127;不知 -128 无原码/反码 |
| 已知补码求真值 | ⭐⭐⭐⭐ | 选择 | 把补码当原码读;不会用"再求补"法 |
| 溢出判断 | ⭐⭐⭐⭐ | 选择/判断 | 以为异号相加会溢出;不会判断正负溢出 |
| signed/unsigned、char | ⭐⭐⭐ | 选择/程序阅读 | 以为 char 处处有符号;同一位模式两种值 |
| 补码减法变加法原理 | ⭐⭐⭐⭐ | 选择/判断 | 不理解为什么补码能让减法变成加法 |
| 快速求补码技巧 | ⭐⭐⭐ | 手算提速 | "从右数第一个1"法记不牢 |
⭐ 必背速记卡
┌──────────────────────────────────────────────────────┐
│ ⭐ 数据编码必背速记卡 │
├──────────────────────────────────────────────────────┤
│ 1. 正数三码合一;负数:原码→反码(数值位取反)→补码(+1) │
│ 2. n位补码范围:-2^(n-1) ~ 2^(n-1)-1 │
│ 3. 8位补码:-128 ~ 127;16位:-32768 ~ 32767 │
│ 4. -128 的补码是 10000000,没有对应的原码和反码 │
│ 5. 补码三大优势:减法变加法、零唯一、多一个最小负数 │
│ 6. 已知补码求真值:负数的数值位"再求补"(取反+1) │
│ 7. 快速求补码:从右找第一个1,该1及右侧不变,左侧取反 │
│ 8. 同号相加结果变号 → 溢出;异号相加永不溢出 │
│ 9. 全1补码 = -1;全0补码 = 0 │
│ 10. 按补码解释 11111111 = -1,按无符号解释 = 255 │
│ 11. char 的符号性由平台决定,signed char 一定有符号 │
│ 12. 钟表调时理解补码:模12系统中,-2 和 +10 等价 │
└──────────────────────────────────────────────────────┘