%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 ![[02-开发笔记/03-计算机基础/计算机基础#^krybvf]] #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later # 正文 ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-6E9DFE77165EAE78DAD45D6787326D70.png|564]] %% # 计算机中的基本单位—比特/字节/字长 ## 比特位 bit **比特** bit 是 **==数据量==** 的基本单位,也即计算机中的 "**最小信息单元**", **网络带宽和传输速度一般用 bit 进行衡量**。 **网络传输速率、宽带速率、路由器速率**的单位都是 **bps(比特每秒)**,例如 **100 兆宽带为 100M bps**。 ## 字节 byte - **字节** byte 是**计算机中==数据存储的最小单位==(存储单元)**,计算机**存储空间和内存大小**都**使用 byte 衡量**。 - **一个字节**由 **8 位(bit)** 组成,每位是一个二进制数 0 或 1。 - 一个字节可以表示 $2^8=256$ 种不同的值,范围为 $[0, 255]$。 - **字节** byte 也是 **==最小的可寻址内存单位==**(Addressable Unit): - 从逻辑上来说,**内存**被视为一个**连续的字节数组**,称之为"**==虚拟内存==**",其中**每个字节都有其==唯一的地址==标识**(数组索引),这些**内存地址从 0 开始**,所有**可能地址的集合**即称之为 "**==虚拟地址空间==**"。 ##### 常用单位换算 | 单位 | 等价的小一级单位 | 等价的字节 | | --- | -------- | ---------- | | PB | 1024 TB | $2^{50}$ B | | TB | 1024 GB | $2^{40}$ B | | GB | 1024 MB | $2^{30}$ B | | MB | 1024 KB | $2^{20}$ B | | KB | 1024 B | $2^{10}$ B | <br> ## 字长 Word size **==字长==(word size)** 是计算机系统的一个基本参数,表示**计算机 CPU ==一次性能够处理的最大数据位数==(bit)**,也即 "**CPU 内数据通路的宽度**"。 字长代表了**两项重要指标**: - **数据处理能力**:字长表示 **==CPU 在单个操作周期可以处理的最大数据位数==**。 - 一个 32 位处理器可以一次处理**32 位(4 字节)** 的数据 - 一个 64 位处理器可以一次处理**64 位(8 字节)** 的数据 - **内存寻址能力**:字长决定了 **==计算机系统 "虚拟地址空间" 的最大范围==**,也即 **CPU 的可寻址范围**。 - "**虚拟地址**" 采用 **==一个字长==** 进行编码,对于一个**字长为 $w$ 位的机器**,可表示的**虚拟地址范围为 $0\sim 2^w-1$**,因此程序最多可访问 **$2^w$ 个字节**: - 32 位系统最多只能直接寻址到 **4GB 的内存空间**,**虚拟地址范围是 $0 \sim 2^{32}-1$** ; - 64 位系统理论上可以寻址到 **16EB 的内存空间**,**虚拟地址范围是 $0 \sim 2^{64}-1$** 。 大多数 64 位机器也能运行 32 位机器编译的程序,这是一种向后兼容。 > [!caution] 「**字长**」并非是 「**字**」的长度!两个概念彼此独立,没有关联 > > 字长是 "**CPU 内数据通路的宽度**": > > ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-C0EDCEC11AFDD5146B7E818D816183E9.png|477]] > <br> ## 字 Word x86 体系结构中,用术语 "**字"**(word) 表示 **==2 字节== 16 位**的**数据类型**。 - **双字**(DWORD,也称 long WORD):**4 字节 32 位** - **四字**(QWROD):**8 字节 64 位** ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-A4F29B98B40F32CDD196B669E729684C.png|578]] <br><br><br> # 多字节数据的地址及存储方式——大端模式与小端模式 > [!NOTE] LSB 和 MSB > > - **最低有效字节**(Least Significant Byte,**LSB**) > - **最高有效字节**(Most Significant Byte,**MSB**) 计算机中,"**==多字节数据的地址==**" 取的是**其占用的 "==最小地址=="**。 (在大端模式下,即 MSB 所在的地址;在小端模式下,即 LSB 所在的地址) **多字节数据在内存中的 "==存储顺序=="** (也称 "**==字节序==**")则有两种不同方式: - **大端模式**(Big Endian): 数据的 **==高位==字节**存储在**内存的==低地址==** 上 - **小端模式**(Littel Endian):数据的 **==低位==字节**存储在**内存的==低地址==** 上 - 即**数据的低位字节对应低地址**,**高字节对应高地址** ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-C2A4578626D39B509C941904038D38D5.png|645]] 实际应用: - 在**指令集架构**中: - 在 **Intel x86、x86-64** 架构中,采用 **==小端模式==**; - 许多**RISC 架构**(如 PowerPC)默认采用**大端模式**; - 在**网络协议**中,通常采用**大端模式**(也称**网络字节序**); - 在**图片格式**存储中: - GIF 是小端模式,JPEG 则是大端模式 > [!NOTE] 小端法字节序书写 > > 小端法**书写字节序列的自然方式是==最低位字节在左边==,==最高位字节在右边==**(与常规数字书写正好相反) > > 例如 `0x200b43` 这一数据的**字节序**应该写为 `43 0b 20 00`。 > > 对多字节数据的读取即**从低地址开始**,**读取得到数据的最低位字节**,再往后。 <br> ## 如何判断系统的字节序? > <font color="#c0504d">❓如何判断系统是大端模式还是小端模式?</font> ^krybvf 存一个**多字节数据**,从其**最低地址起**,**逐字节地访问该数据的内存表示**,从而判断: ```cpp #include <iostream> using namespace std; int main(int argc, char** argv) { // int: 4字节32位, 赋值为1 unsigned int x = 1; // 将int的地址int*p类型强制转换为unsigned char*类型, 即指向单字节的指针 unsigned char* bytePtr = reinterpret_cast<unsigned char*>(&x); // bytePtr指向的是int型占有的"最低地址", 检查该地址的值是否为1 // 若是1, 则为小端模式(低字节在低地址). 反之, 为大端模式 cout << (int) *bytePtr << endl; // cout << (int) bytePtr[0] << endl; // 与上等价 return 0; } ``` <br><br><br> # 计算机语言 计算机语言包含三层(由**最底层/机器可读**=> **高层抽象/人类可读**): - **机器语言**(机器指令):最底层的二进制码,直接控制硬件 - **汇编语言**(汇编指令):机器语言的符号化表示,人类易读; - **高级程序语言**(C、C++、Java、Python 等):提供高度抽象、硬件无关的编程语言,供人类编程。 ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-3E334F21E31D30C225E5C58DB78EC0A7.png|215]] 汇编语言是对机器语言的文本表示,当使用**汇编语言**编程时,程序员**必须指定 CPU 所需执行的具体指令**。 而**高级程序语言**则提供了较高的抽象,**屏蔽了机器(处理器)的执行细节**。 <br> ## 机器语言 Machine Language **机器语言**(也称**机器指令**、**机器码**)是计算机唯一能够**理解和执行的指令**,由**纯粹的==二进制码== 0/1 序列**构成。 **机器指令直接控制计算机==硬件==执行基本操作**,例如执行加法、数据移动、跳转等。 不同的**指令集架构(ISA)** 下所定义的机器指令不同,无法跨平台使用。 > [!example] > > 例如二进制指令 `10110000 01100001` 的含义取决于具体的**指令集架构**,在某些处理器上,它可能表示将值`0x61`(十六进制)加载到寄存器。 > > [!NOTE] 理解 "机器视角" > > 从机器的角度来看,**程序与数据都仅仅只是由二进制码 0/1 构成的字节序列**。 > > **不同的机器类型**通常具有**不同且不兼容的指令集架构 ISA**,同时**不同的操作系统**也会有**不同的编码规则**, > > 因此,**==编译后的二进制代码==很少能够"直接"在不同机器和操作系统组合之间进行移植**。 <br> ## 汇编语言 Assembly Language **汇编语言**(也称**汇编指令**)是一种低级程序语言,使用**符号化的指令**(助记符)和**操作码**来表示机器指令,人类易读,但需要由 **==汇编器==(Assembler)** 将其翻译为机器语言以供计算机执行。 ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-04D152B424C7BB270B1E481019711434.png|568]] 实际上,「**汇编语言**」包含三类指令: - **汇编指令**:机器指令的文本助记符,每一条**汇编指令**通常对应一条**机器指令**。 - **伪指令**:没有对应的机器码,**由编译器执行**,计算机并不执行 - **其他符号**:如 `+,-,*,/` 等,**由编译器识别**,没有对应的机器码。 > [!example] > > x86 汇编语言 `MOV AL, 61h` 表示将十六进制值 `61` 加载到寄存器 `AL` 中, > 对应的机器语言指令可能即为 `10110000 01100001` <br> ## 高级程序语言 提供**较高抽象层次**的编程语言,硬件无关,**人类易读**且提供了更多、更灵活、更强大的功能特性。 **高级程序语言编写的源代码**需要最终转换为**机器指令**,才能供计算机执行,通常由两种方式: - (1)由 **==编译器==(compiler)** 编译为**汇编语言**,再由 **==汇编器==**(Assembler)转换为**机器指令**; - 例如 C,C++语言 - (2)由 **==解释器==(interpreter)** 编译为**字节码**,再由特定工具**将字节码解释为机器指令**。 - 例如 Java,Python 语言 > [!NOTE] 「**字节码**」 > > 「字节码」是高级程序语言与机器语言之间的一种**中间表示**,**既不是高级语言代码,也不是汇编语言或机器语言**。不同语言中的 "字节码" 各不相同。 <br><br> ### 源代码到机器指令的转换 ###### C/C++ 源代码的转换过程 参见[[02-开发笔记/03-计算机基础/编译与链接/编译与链接|编译与链接]] ###### Java 源代码的转换过程 - Java 源代码保存为 `.java` 文件; - **Java 编译器**(`javac`)将 Java 源代码编译为**字节码**,存储在`.class`文件中。 - **Java 虚拟机**(JVM)将字节码解释为 "**机器指令**",生成**二进制可执行文件** Java 字节码是平台无关的,**在任何安装了 JVM 的系统上都能运行**,因此 Java 非常适用于跨平台开发。 > [!NOTE] **Java 的字节码**可以视为 "**==虚拟机`JVM` 的机器指令==**"(正如其名,"**虚拟机器**"),再由 `JVM` 翻译为**平台特定的机器指令**。 ###### Python 源代码的转换过程 - Python 源代码保存为 `.py` 文件 - **Python 解释器** 将 python 源代码翻译为**字节码**(通常可能只在内存中生成而不会产生文件) - 字节码文件后缀为 `.pyc`,通常存储在源代码同目录下的 `__pycache__/` 目录中。 - **Python 解释器** 再将字节码逐句解释为 "**机器指令**",**直接执行**(不生成可执行文件) #### 编译型语言与解释型语言 - **编译型**语言:**源代码需要先编译生成 "==二进制可执行文件=="(机器级目标程序)再运行 - 特点: - **编译过程可进行全面的语法和语义检查**; - **编译生成的可执行文件**通常**与特定的硬件和操作系统相关**,不具有可移植性。<br>要在不同的平台上运行,需要重新编译源代码。 - **编译后的程序可直接执行,通常具有较高的执行速度** - 典型代表:C、C++、Go、Rust、Java - **解释型**语言:**不需要编译为可执行文件**,源代码**由解释器==逐行翻译为机器指令==并立即执行 - 特点: - **每次运行代码都需要解释器参与**,逐行翻译解析,因此**运行速度较慢**。 - **代码在执行时才被翻译和检查,许多错误只有在运行时才能发现** - **平台无关**——**可在安装了解释器的任何平台上运行** - 典型代表:Python、JavaScript、Ruby、Shell > [!NOTE] > > 一些现代编程语言(如Java、Python)**实际上采用了混合模式**,既有编译步骤也有解释步骤, > 但主要根据是否会 "**==生成二进制可执行文件==**" 来区分。 > > - Java 先将源代码编译成字节码,然后由JVM解释或JIT编译执行; > - Python 先将源代码编译成字节码,然后由解释器执行字节码。 <br><br><br> # 指令集架构 ISA > **指令集架构**(Instruction Set Architecture, ISA),也称**指令集体系结构**; ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-E6FF34E5BF647CA269A3B9725E37810F.png|842]] **指令集架构(ISA)** 是一套**关于计算机处理器 CPU 的标准**——**==CPU 向软件提供的、操作 CPU 的接口==(即各种机器指令)** ISA 定义了 CPU 支持的**指令集**、**指令格式**、**数据类型与格式**、**寄存器**、**内存寻址方式**、**中断及异常处理机制**、**与 I/O 设备间的通信机制**等,提供了**处理器与软件(包括 OS )之间的 "二进制接口" (ABI)**。 - **指令集**: - 定义了处理器可以执行的 **==所有指令的集合==**,包括**数据处理指令**(如加法、减法),**数据传输指令**(如加载、存储),**控制流指令**(如跳转、分支)等。 - ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-AAF21B259B593792FEC6738CA161D23F.png|535]] - ISA 规定了每条指令的操作数、操作数位置、操作数类型。 - **指令格式**: - 定义了每条指令的二进制机器语言表示 - 包括操作码(opcode)、操作数字段、地址模式等。 - **数据类型和格式**: - 规定了处理器可以**直接处理的操作数的类型,如整数、浮点数、字符**等, - 规定了这些数据**在内存中的表示方式和存储方式** - **寄存器**: - 定义了**处理器内部的寄存器的名称、编号、大小和用途**。 - 寄存器可以是通用寄存器、浮点寄存器、专用寄存器(如程序计数器、状态寄存器)等。 - **内存方面**: - 规定了**操作数**在内存空间中的存放方式(大端/小端模式) - 规定了处理器**如何寻址内存**,包括**内存地址的大小、内存寻址方式**(如直接寻址、间接寻址、基址加偏移寻址)等。 - **中断和异常处理**: - 定义处理器如何响应和处理中断和异常,包括中断向量、优先级、处理流程等。 - **I/O机制**: - 规定处理器与输入输出设备之间的接口和通信方式。 > [!NOTE] ISA 是 CPU 与软件(包括操作系统)之间的接口 > > 在同一指令集架构下,不同的 CPU 型号与不同操作系统之间均能适配。 > > 例如 64 位的 Window 或 Linux 系统基于 x86-64 架构,能够运行在任何基于同一架构的 CPU 之上。 ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-8237B479CCEA5AB9E815BA9CF49E1326.png|512]] <br><br> ## 「精简指令集 RISC」 与 「复杂指令集 CISC」 CISC 和 RISC 是两种不同的 **ISA 设计理念**: - **复杂指令集**(CISC, Complex Instruction Set Computer) - **精简指令集**(RISC, Reduced Instruction Set Computer) ##### 精简指令集(RISC) RISC 强调 **==简化==指令集的复杂性**,使用更少、更简单的指令来执行程序 代表架构:**ARM**、**MIPS**、**RISC-V** 等 特点: - **指令数量少且简单**:RISC 指令集包含较少的指令,每条指令执行的操作简单而快速。 - **固定指令长度**:所有指令通常具有相同的长度,简化了指令解码和执行的过程。 - **单周期指令执行**:大多数指令在一个时钟周期内完成,提升了指令执行的速度。 - **大量通用寄存器**:RISC 架构通常提供更多的寄存器,以减少内存访问次数,提高操作效率。 - **Load/Store 架构**:只有加载(Load)和存储(Store)指令访问内存,其余指令只在寄存器之间操作,减少了内存访问的复杂性。 - **简化的寻址模式**:RISC 架构使用简单的寻址模式,使得指令的解码和执行更加高效。 ##### 复杂指令集(CISC) CISC 强调**指令集的多样性和复杂性**,使用较多、较复杂的指令来执行程序。 代表架构:**x86**(Intel、AMD)、VAX、IBM System/360 等。 特点: - **指令数量多且复杂**:CISC 指令集包含大量指令,每条指令可以执行复杂的操作,可能涉及多个时钟周期。 - **可变指令长度**:指令长度不固定,根据操作的复杂性而变化。 - **多周期指令执行**:许多指令需要多个时钟周期才能完成,指令执行时间不固定。 - **较少通用寄存器**:CISC 架构通常提供较少的寄存器,更多地依赖内存访问。 - **内存到内存操作**:指令可以直接在内存位置之间操作,不需要先加载到寄存器。 - **丰富的寻址模式**:CISC 架构支持多种复杂的寻址模式,使得指令可以直接访问复杂的数据结构。 <br> ## 常见的指令集架构 - **x86 架构**: - 由 Intel 和 AMD 等公司广泛使用的**复杂指令集计算(CISC)架构**,广泛应用于个人计算机和服务器 - **ARM 架构**: - 由 Arm公司设计的**精简指令集计算(RISC)架构**,广泛应用于移动设备、嵌入式系统和物联网设备。 - **RISC-V 架构**: - 一种**开源的RISC架构**,受到学术界和工业界的广泛关注和支持 - **MIPS 架构**: - 一种经典的RISC架构,广泛应用于教育和嵌入式系统。 ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-E523A9234C0EFA71620628AD570E0E54.png|730]] <br> ## 关于 x86 与 x86-64 架构 - **x86 架构**(也称 x86-32、**Intel 32**、**IA-32**):**32 位的体系结构** - **x86-64 架构**(也称 x64、**AMD-64**、Intel 64):**64 位的体系结构**(基于 x86 的 64 位扩展) 64 位指令集可以运行 64 位数据指令,针对的是 64 位的 CPU(即**CPU 一次可提取 64 位数据**) 64 位 CPU 中**通用寄存器**(General-Purpose Registers,GPRs ) 的**数据宽度为 64 位**。 > [!info] 历史由来[^1] > > - **x86 也称 IA-32**(Intel Architecture 32bit),是由英特尔公司于 1985 年最早推出的。 > - IA-64 是由英特尔与惠普公司曾经联合推出的 64 位指令集,**不兼容 x86**,导致市场惨淡被淘汰 > - **x86-64 也称 AMD-64**,是由 AMD 公司发明的基于 x86 架构的 64 位扩展。 > > > [!info] x86-64 是现代 CPU 最主流的架构。 > > 现代操作系统基本都已经淘汰了 32 位版本,通常都是**64 位系统**,也就是针对 x86-64 架构的系统版本。 > > - **Windows 系统**:Windows Vista, Windows 7, Windows 8/8.1, Windows 10, 和 Windows 11 都有 x86-64 版本。 > > - **Linux 系统**:几乎所有主流的 Linux 发行版都支持 x86-64 架构。 <br><br><br> # API 与 ABI 操作系统提供的接口包括两种:API 与 ABI - **应用程序==编程接口==** **API**(Application Programming Interface) - **应用程序==二进制接口== ABI**(Application Binary Interface) > [!example] > > - C 标准库中的 `mmap`、`munmap`、`malloc`、`free` 接口是**面向 C 语言编程提供的,源代码层面的接口**,属于 API。 > - C 标准库在实现这些接口时使用的 `mmap`、`munmap`、`brk`、`sbrk` **==系统调用==** 属于 ABI。 ### API API 是**源代码/语言级别的**,供高级编程语言**编写应用程序时调用**,是**源代码层面使用的接口**。 **操作系统提供的 API** (例如 Linux 系统库 Glibc)定义了操作系统所提供的特定功能和服务,如文件操作、内存管理、硬件访问等。 API 接口通常由语言自身的标准库提供,例如 C 标准库中包含的 `mmap`、`munmap`、`malloc`、`free` 等函数 API,提供了与操作系统的交互。 > [!NOTE] Unix/类 Unix 系统的 **POSIX 标准**、**UNIX System V 标准**、**Unix BSD 标准** 都属于 API。 ### ABI ABI **二进制==机器指令==层面的接口**,定义了**应用程序的二进制文件(可执行文件)如何与操作系统进行交互**,从而在特定操作系统和硬件上运行。 ABI 定义了**二进制接口规范**,包括**二进制文件格式**(例如 Linux 下的 ELF 格式与 Windows 下的 EXE 文件格式)、**数据模式**(大端模式与小端模式)、**数据结构**、**寄存器的使用方式**,以及**调用和返回约定**(参数传递与返回值处理),受**机器硬件、操作系统、编译器、链接器**等多种因素的影响。 > [!NOTE] ABI 的影响因素 [^2] > > ![[_attachment/02-开发笔记/03-计算机基础/计算机基础.assets/IMG-计算机基础-14622F15FA4B271BD391436613B4B5F5.png|503]] <br><br> # 参考资料 # Footnotes [^1]: [X86、X64和X86\_64区别](http://www.360doc.com/content/19/0828/10/19244573_857512066.shtml) [^2]: 《程序员的自我修养:链接、装载与库》