数据表示与位运算
数据表示与位运算
一、整数的内部表示:补码 (Two's Complement)
计算机中,所有数据都以二进制(0和1)形式存储。对于整数,需要一种方式来表示正数、负数和零。虽然有几种方法(如原码、反码),但现代计算机普遍使用补码来表示有符号整数。
为什么用补码?
补码的设计非常巧妙,它统一了加法和减法运算。计算 A - B 可以直接转换为计算 A + (-B),这样硬件上只需要实现加法器电路即可,极大地简化了CPU的设计。
补码规则:
-
正数和零:
-
补码与它的原码(标准的二进制表示)相同。
-
最高位(最左边的位)为符号位,正数的符号位是 0。
-
示例 (8位整数):
5的补码是0000 0101
-
-
负数:
-
负数的补码是其对应正数的原码经过“按位取反,再加一”得到的。
-
负数的符号位是 1。
-
示例 (8位整数,计算 -5 的补码):
- 先取
5的原码:0000 0101 - 按位取反 (0变1,1变0):
1111 1010 - 末位加一:
1111 1011
- 所以,
-5在8位系统中的补码表示就是1111 1011。
- 先取
-
从补码求原值:
如果一个补码的最高位是1,说明它是一个负数。要求它的绝对值,可以再次执行“按位取反,再加一”的操作。
-
示例 (计算
1111 1011代表的值):- 这是一个负数(最高位是1)。
- 按位取反:
0000 0100 - 末位加一:
0000 0101(这是5)
- 所以,
1111 1011代表的值是-5。
重要特例:
对于一个n位的有符号整数,其表示范围是 -2^(n-1) 到 2^(n-1) - 1。
- 对于8位整数,范围是
-128到127。 -1的补码总是全1,如1111 1111(8位) 或FFFF FFFF(32位)。
二、字节序 (Byte Order / Endianness)
当一个数据类型(如 int,通常占4字节)需要多个字节来存储时,这些字节在内存中如何排列的顺序就是字节序。
-
小端序 (Little-Endian):
-
规则:数据的低位字节 (Least Significant Byte, LSB) 存放在内存的低地址处,高位字节存放在高地址处。
-
特点:“低对低,高对高”。
-
示例:将32位整数
0x12345678存放到地址0x100开始的内存中。- 内存地址
0x100:0x78(低位字节) - 内存地址
0x101:0x56 - 内存地址
0x102:0x34 - 内存地址
0x103:0x12(高位字节)
- 内存地址
-
使用者:Intel、AMD 的 x86/x64 架构CPU。因此,你使用的 Windows 系统是小端序。
-
-
大端序 (Big-Endian):
-
规则:数据的高位字节 (Most Significant Byte, MSB) 存放在内存的低地址处,低位字节存放在高地址处。
-
特点:“高对低,低对高”,符合人类的阅读习惯。
-
示例:将32位整数
0x12345678存放到地址0x100开始的内存中。- 内存地址
0x100:0x12(高位字节)
- 内存地址
-
-
内存地址
0x101:0x34- 内存地址
0x102:0x56 - 内存地址
0x103:0x78(低位字节)
- 内存地址
-
使用者:一些RISC架构CPU (如旧的PowerPC)、一些ARM处理器(可配置)、网络协议(如TCP/IP中的IP地址和端口号,又称网络字节序)。
三、字符编码基础 (Character Encoding)
-
ASCII (American Standard Code for Information Interchange):
-
定义:最早和最基本的编码,使用7位二进制数(通常存放在一个8位的字节中,最高位为0)来表示128个字符。
-
内容:包括英文字母(大小写)、数字(0-9)、标点符号和一些控制字符。
-
示例:
- 字符
'A'的ASCII码是65(十六进制0x41)。
- 字符
-
-
字符
'0'的ASCII码是48(十六进制0x30)。 -
局限:只能表示英语字符,无法表示中文、日文等其他语言。
-
Unicode:
-
定义:一个字符集标准,旨在为世界上每一种语言的每一个字符都分配一个唯一的数字编号,这个编号称为码点 (Code Point)。
-
示例:
'A'的码点是U+0041。
-
-
汉字
'中'的码点是U+4E2D。 -
注意:Unicode只定义了码点,它本身不是一种编码方式。如何将这些码点存储为字节序列,则由具体的编码方式(如UTF-8, UTF-16)决定。
-
UTF-8 (Unicode Transformation Format - 8-bit):
-
定义:目前互联网上使用最广泛的一种 Unicode 编码实现方式。
-
特点:
- 可变长度编码:根据码点的大小,一个字符可能使用1到4个字节来表示。
- 兼容ASCII:对于ASCII字符(码点0-127),UTF-8编码与ASCII编码完全相同,只使用1个字节。这使得UTF-8具有很好的向后兼容性。
- 对于其他字符(如汉字),通常使用3个字节来编码。
-
四、位运算符 (Bitwise Operators)
位运算符直接对整数在内存中的二进制位进行操作。
| 运算符 | 名称 | 规则 | 示例 (a=60, b=13) | 结果 |
|---|---|---|---|---|
| & | 按位与 (AND) | 两个位都为1时,结果为1;否则为0。 | a = 0011 1100 b = 0000 1101 a & b |
0000 1100 (12) |
| | | 按位或 (OR) | 两个位中至少有一个为1时,结果为1;否则为0。 | a = 0011 1100 b = 0000 1101 a | b |
0011 1101 (75) |
| ^ | 按位异或 (XOR) | 两个位不同时,结果为1;相同时为0。 | a = 0011 1100 b = 0000 1101 a ^ b |
0011 0001 (49) |
| ~ | 按位取反 (NOT) | 翻转所有位,0变1,1变0。 | a = 0011 1100 ~a |
1100 0011 (-61) |
| << | 左移 (Left Shift) | a << n 将 a 的所有位向左移动 n 位,右边空出的位补0。 | a = 0011 1100 a << 2 |
1111 0000 (240) |
| >> | 右移 (Right Shift) | a >> n 将 a 的所有位向右移动 n 位。 | a = 0011 1100 a >> 2 |
0000 1111 (15) |
右移 (>>) 的重要说明:
-
对于无符号数 (unsigned),左边空出的位总是补0(逻辑右移)。
-
对于有符号数 (signed),行为是由实现定义的:
- 算术右移 (Arithmetic Shift):左边空出的位补充符号位(即正数补0,负数补1)。这是最常见的实现,可以保持数的正负。
-
逻辑右移 (Logical Shift):左边空出的位总是补0。

浙公网安备 33010602011771号