数据表示与位运算

数据表示与位运算

一、整数的内部表示:补码 (Two's Complement)

计算机中,所有数据都以二进制(0和1)形式存储。对于整数,需要一种方式来表示正数、负数和零。虽然有几种方法(如原码、反码),但现代计算机普遍使用补码来表示有符号整数。

为什么用补码?

补码的设计非常巧妙,它统一了加法和减法运算。计算 A - B 可以直接转换为计算 A + (-B),这样硬件上只需要实现加法器电路即可,极大地简化了CPU的设计。

补码规则:

  1. 正数和零

    • 补码与它的原码(标准的二进制表示)相同。

    • 最高位(最左边的位)为符号位,正数的符号位是 0

    • 示例 (8位整数):

      • 5 的补码是 0000 0101
  2. 负数

    • 负数的补码是其对应正数的原码经过“按位取反,再加一”得到的。

    • 负数的符号位是 1

    • 示例 (8位整数,计算 -5 的补码):

      1. 先取 5 的原码: 0000 0101
      2. 按位取反 (0变1,1变0): 1111 1010
      3. 末位加一1111 1011
      • 所以,-5 在8位系统中的补码表示就是 1111 1011

从补码求原值:

如果一个补码的最高位是1,说明它是一个负数。要求它的绝对值,可以再次执行“按位取反,再加一”的操作。

  • 示例 (计算 1111 1011 代表的值):

    1. 这是一个负数(最高位是1)。
    2. 按位取反0000 0100
    3. 末位加一0000 0101 (这是5)
    • 所以,1111 1011 代表的值是 -5

重要特例:

对于一个n位的有符号整数,其表示范围是 -2^(n-1) 到 2^(n-1) - 1。

  • 对于8位整数,范围是 -128127
  • -1 的补码总是全1,如 1111 1111 (8位) 或 FFFF FFFF (32位)。

二、字节序 (Byte Order / Endianness)

当一个数据类型(如 int,通常占4字节)需要多个字节来存储时,这些字节在内存中如何排列的顺序就是字节序

  1. 小端序 (Little-Endian)

    • 规则:数据的低位字节 (Least Significant Byte, LSB) 存放在内存的低地址处,高位字节存放在高地址处。

    • 特点:“低对低,高对高”。

    • 示例:将32位整数 0x12345678存放到地址 0x100开始的内存中。

      • 内存地址 0x1000x78 (低位字节)
      • 内存地址 0x1010x56
      • 内存地址 0x1020x34
      • 内存地址 0x1030x12 (高位字节)
    • 使用者:Intel、AMD 的 x86/x64 架构CPU。因此,你使用的 Windows 系统是小端序

  2. 大端序 (Big-Endian)

    • 规则:数据的高位字节 (Most Significant Byte, MSB) 存放在内存的低地址处,低位字节存放在高地址处。

    • 特点:“高对低,低对高”,符合人类的阅读习惯。

    • 示例:将32位整数 0x12345678 存放到地址 0x100 开始的内存中。

      • 内存地址 0x1000x12 (高位字节)
  • 内存地址 0x1010x34

    • 内存地址 0x1020x56
    • 内存地址 0x1030x78 (低位字节)
  • 使用者:一些RISC架构CPU (如旧的PowerPC)、一些ARM处理器(可配置)、网络协议(如TCP/IP中的IP地址和端口号,又称网络字节序)。


三、字符编码基础 (Character Encoding)

  1. ASCII (American Standard Code for Information Interchange)

    • 定义:最早和最基本的编码,使用7位二进制数(通常存放在一个8位的字节中,最高位为0)来表示128个字符。

    • 内容:包括英文字母(大小写)、数字(0-9)、标点符号和一些控制字符。

    • 示例:

      • 字符 'A' 的ASCII码是 65 (十六进制 0x41)。
  • 字符 '0' 的ASCII码是 48 (十六进制 0x30)。

  • 局限:只能表示英语字符,无法表示中文、日文等其他语言。

  1. Unicode

    • 定义:一个字符集标准,旨在为世界上每一种语言的每一个字符都分配一个唯一的数字编号,这个编号称为码点 (Code Point)

    • 示例:

      • 'A' 的码点是 U+0041
  • 汉字 '中' 的码点是 U+4E2D

  • 注意:Unicode只定义了码点,它本身不是一种编码方式。如何将这些码点存储为字节序列,则由具体的编码方式(如UTF-8, UTF-16)决定。

  1. 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。

posted @ 2025-05-24 17:59  phen  阅读(152)  评论(0)    收藏  举报