计算机本质上是一大堆电子开关。每个开关只有两种状态:通电或断电。我们用 1 表示通电、0 表示断电。
这样一个「只能是 0 或 1」的最小信息单位,就叫做 位(bit,比特)。它是信息世界里不可再分的「原子」。
一个开关只能表达「是 / 否」两种可能——信息量太小了。于是我们把多个开关排成一排一起用,能表达的组合就会指数级增长。
把 8 位 排成一排打包在一起,就构成了 1 个字节(byte)。字节是计算机存储和处理数据时最常用的「基本包装单位」——内存大小、文件大小,算的几乎都是字节。
下面是一个真实的字节。每一位都有自己的权重(位权),从右到左依次是 1、2、4、8……最左边是 128。把所有「亮起」的位权加起来,就是这个字节代表的数值。点击下面的方块拨动它们试试:
试着把所有位都点亮:你会得到 11111111,也就是十进制的 255。再加 1 就「进位溢出」了。这说明:一个字节能表示的最大无符号整数就是 255。
8 这个数字并不是物理定律决定的,更多是历史与工程权衡的结果。早期计算机的字长五花八门(6 位、7 位、9 位都有过)。
真正让 8 位「定型」的关键,是 1960 年代 IBM System/360 的普及,以及一个现实需求:用 8 位刚好能舒服地编码一个英文字符(包括大小写字母、数字、标点和一些控制符)。
8 位 = 2⁸ = 256 种组合。当年的 ASCII 字符只需要 128 个编码,8 位绰绰有余还留了一倍余量。而且 8 是 2 的幂,方便对半切分(半字节 = 4 位 = 1 个十六进制位),电路设计很整齐。
从此,「1 字节 = 8 位」成了几乎所有现代计算机的事实标准。注意:严格的标准术语里,明确指 8 位的单位叫 octet(八位组),在网络协议规范中常见。
同一个数值,可以用不同的「进制」来书写。计算机内部是二进制,人类习惯十进制,而程序员最爱十六进制——因为每 4 个二进制位刚好对应 1 个十六进制位,一个字节正好写成 2 个十六进制字符(如 0xFF),简洁又不丢信息。
试着输入 255,看二进制变成 11111111、十六进制变成 FF。再试 16,注意十六进制是 10——这正是「逢十六进一」。本转换器以单字节(0–255)为范围演示
规律极其简单:每多 1 位,组合数就翻一倍。n 个位能表示 2ⁿ 种不同的状态。这就是为什么计算机里到处都是 2 的幂。
| 位数 | 组合数 2ⁿ | 说明 |
|---|---|---|
| 1 位 | 2 | 是 / 否 |
| 2 位 | 4 | 00 01 10 11 |
| 4 位 | 16 | 半字节 = 1 个十六进制位 |
| 8 位 | 256 | 1 字节 · 可表示 0–255 |
| 16 位 | 65,536 | 2 字节 · 一个常见的「短整型」 |
| 32 位 | 约 42.9 亿 | 4 字节 · IPv4 地址总数就是它 |
| 64 位 | 约 1.8×10¹⁹ | 8 字节 · 现代 CPU 的主流字长 |
翻倍的力量很惊人:仅仅 64 位,能表示的数量就超过了地球上沙粒的总数。
一个字节有 256 种组合。如果只表示非负整数,就是 0–255(无符号 unsigned)。但我们也需要负数,于是用其中一半组合表示负数——这就是有符号 signed。
现代计算机几乎都用 补码(two's complement)表示法:最高位(最左边那位)当作符号位。它为 0 时是正数,为 1 时表示负数,此时真实数值 = 无符号值 − 256。
把上面字节实验台切到「有符号」模式,再点亮最高位(128 那位)。你会看到十进制还是越来越大,但「有符号值」却变成了负数(比如 10000000 = 无符号 128,有符号 −128)。这正是补码的魔法:让加减法在硬件上能用同一套电路完成。
所以同样是 11111111 这 8 个位,解释成无符号是 255,解释成有符号补码却是 −1。字节本身只是 0 和 1,怎么解读取决于约定。这是理解数据类型的关键。
字节往上是更大的单位。但这里藏着一个让无数人困惑的坑:同样写「KB」,可能指 1000 字节,也可能指 1024 字节。
因为 1024 = 2¹⁰,最接近 1000 又是 2 的幂,所以内存/操作系统常按 1024 计。而硬盘厂商按 1000 标注容量。于是标称 1 TB 的硬盘(10¹² 字节),在按 1024 换算的系统里只显示约 931 GiB——并没有少,只是两套数法之差。严谨写法应区分 GB(×1000)与 GiB(×1024)。
计算机只存字节,那「中」「あ」「A」「😀」这些字符是怎么存的?答案是字符编码:用一张约定好的表,把字符映射成字节序列。
早期的 ASCII 用 1 个字节表示一个英文字符。但世界上字符远超 256 个,于是有了能容纳全人类文字的 Unicode,给每个字符一个唯一编号(码点,如 U+4E2D)。而 UTF-8 是目前最主流的「把码点存成字节」的方案——它很巧妙:英文字符仍占 1 字节,中文/日文汉字通常占 3 字节,emoji 多为 4 字节。
「字符数」和「字节数」不是一回事。一句 10 个汉字的日文台词,在 UTF-8 里可能占 30 字节左右;如果按字节去截断字符串,很容易把一个汉字「切成两半」变成乱码(俗称 mojibake)。这也是为什么处理 CJK 文本时,要按字符(码点)而非字节来计算长度和切分。
当一个数值需要多个字节存储时(比如 16 位整数 0x1234 要用 2 个字节),还有一个问题:这两个字节谁先谁后?这就是「字节序(endianness)」。
大端把「最重要的字节」放在最前(像人类写数字的习惯),网络传输常用它。小端反过来,x86 / ARM 等主流 CPU 在内存里多用小端。读取二进制文件、网络协议或做引擎逆向时,搞错字节序会读出完全错误的数值——这是底层开发常见的坑。