diff --git a/Doc/0. Philosophy - Intro/0.1 Philosophy - Intro.md b/Doc/0. Philosophy - Intro/0.1 Philosophy - Intro.md new file mode 100644 index 0000000..519061e --- /dev/null +++ b/Doc/0. Philosophy - Intro/0.1 Philosophy - Intro.md @@ -0,0 +1,293 @@ +--- +title: "编程哲学导论" +subtitle: "Programming Philosophy - Introduction" +version: "1.0" +category: "哲学篇 · 导论" +order: 0.1 +tags: [编程, 哲学, 导论, 基础概念] +--- + +# 0.1 编程哲学导论 + +> **本节导读**:从最本质的角度理解"编程"的含义,建立对代码、编译器、程序的核心认知,并初步了解程序设计的基本哲学思想。 + +--- + +## 一、什么是编程? + +### 1.1 词源解析 + +| 汉字 | 含义 | 词性 | 说明 | +|:----:|------|:----:|------| +| **编** | 编写 | 动词 (verb) | 编写代码的动作 | +| **程** | 程序 / 程式 | 名词 (noun) | 具有格式和顺序的结构 | + +### 1.2 核心定义 + +> **编程 (Programming)**:按照一定的 **格式** 与 **顺序** 编写代码的过程。 + +我们编程的核心目标,是对各种各样的 **文件** 进行操作。 + +#### 直观类比 + +可以将编程与 **烹饪** 做类比: + +| 烹饪 | 编程 | +|------|------| +| 菜谱 (格式 + 顺序) | 代码 / 算法 | +| 食材 (原料) | 数据 / 文件 | +| 菜肴 (最终产出) | 可执行程序 | +| 厨师 (执行者) | CPU / 计算机 | + +--- + +## 二、核心概念 + +### 2.1 什么是代码? + +**代码 (Code)** 本质上是 **文本文件**,即由 ASCII 字符组成的纯文本。 + +#### 常见代码文件扩展名 + +| 语言 | 扩展名 | 说明 | +|------|--------|------| +| C 语言 | `.c` | C 源文件 | +| C 语言 | `.h` | C 头文件 | +| C++ | `.cpp` | C++ 源文件 | +| C++ | `.hpp` | C++ 头文件 | +| C++ | `.cc` / `.cxx` | C++ 源文件(替代写法) | + +> **NOTE**:`.c` / `.h` 通常用于 C 语言代码;`.cpp` / `.h` / `.cc` / `.cxx` / `.hpp` 通常用于 C++ 代码。 + +> **NOTE**:只要是合法的 C 或 C++ 的 ASCII 文本(无论使用何种扩展名),都可以被称为 **代码**。 + +#### 代码示例 + +**示例 — C 语言 "Hello, World"**: + +```c +#include + +int main() +{ + printf("Hello, World!\n"); + + return 0; +} +``` + +> **NOTE**:以上代码就是一个纯 ASCII 文本文件,保存为 `main.c` 后,它就是一段 **代码**。无论你将扩展名改为 `.txt`、`.abc` 甚至不加扩展名,只要内容合法,它依然是代码——只是编译器可能无法自动识别而已。 + +--- + +### 2.2 什么是编译器? + +**编译器 (Compiler)** 是将 **代码** 转换为 **可执行文件** 的工具。 + +#### 直观类比 + +可以将编译器类比为 **翻译官**: + +| 翻译官 | 编译器 | +|--------|--------| +| 输入:外文原文 | 输入:源代码 (C/C++) | +| 处理:语法分析、语义理解 | 处理:词法/语法/语义分析 | +| 输出:本国语言译文 | 输出:机器码 (可执行文件) | + +如果原文有语法错误,翻译官会报错并指出问题位置 —— 编译器也是如此。 + +#### 输入与输出 + +``` +┌─────────────────────┐ ┌─────────────────────┐ +│ Input │ →→→→ │ Output │ +│ │ │ │ +│ File, Code │ Compiler │ Executable File, │ +│ (ASCII Text) │ │ Linker Output │ +└─────────────────────┘ └─────────────────────┘ +``` + +#### 编译流程全景图 + +以 Windows 上的编译流程为例: +``` + Source File(s) + │ + ▼ + ┌──────────────┐ + │ Preprocessor │ + └──────┬───────┘ + │ + ▼ + ┌──────────────┐ + │ Compiler │ + └──────┬───────┘ + │ + ▼ + ┌──────────────┐ + │ Assembler │ + └──────┬───────┘ + │ + ▼ + ┌──────────────┐ + │ Linker │ + └──────┬───────┘ + │ + ▼ +Executable File (.exe) +``` + +> **REFERENCE**:关于编译流程各阶段的详细说明,请参阅 [→ 0.2 编程基础](./0.2%20Philosophy%20-%20Basic.md#三编译流程详解) + +--- + +### 2.3 什么是程序? + +**程序 (Program)** 是经过编译后生成的可执行文件,是计算机能够直接理解和执行的指令集合。 + +#### 直观类比 + +| 概念 | 类比 | +|------|------| +| **源代码** | 乐谱 (人可读,但不能直接发声) | +| **编译器** | 钢琴家 (将乐谱"翻译"为按键动作) | +| **程序/可执行文件** | 录好的音频文件 (可直接播放) | +| **运行程序** | 播放录音 (计算机执行指令) | + +#### 示例 + +``` +main.c (Source Code) --[Compile]--> main.exe (Program) --[Run]--> Output +Human Readable Machine Executable User Sees +``` + +--- + +## 三、基本设计哲学 + +> 以下是我对程序基本设计哲学的理解与总结: + +### 3.1 抽象 (Abstraction) + +用代码的方式 **描述问题**,而不纠结于实现细节。 + +- 将复杂现实简化为可计算的模型 +- 关注 **"做什么"** 而非 **"怎么做"** +- 通过接口隐藏底层复杂性 + +#### 示例 + +**场景:发送一封电子邮件** + +| 层级 | 抽象程度 | 你需要关心的事 | +|:----:|----------|----------------| +| **用户层** | 最高 | 收件人地址、邮件标题、正文内容 | +| **应用层** | 高 | 调用 `smtp.send(to, subject, body)` | +| **协议层** | 中 | SMTP 握手、HELO/EHLO、DATA 命令 | +| **传输层** | 低 | TCP 三次握手、数据包分片与重组 | +| **物理层** | 最低 | 电信号 / 光信号 / 无线电波 | + +**抽象的意义**:当你写 `print("Hello")` 时,你不需要知道显卡如何渲染像素、操作系统如何调度显示驱动——这就是抽象的力量。 + +### 3.2 模块化 (Modularization) + +将复杂问题 **分解** 为多个相对独立的子问题,每个子问题构成一个 **模块**。 + +``` +Complex Problem + | + +---> Module A ---> Sub-problem A + +---> Module B ---> Sub-problem B + +---> Module C ---> Sub-problem C +``` + +**示例 — 开发一个计算器程序**: + +``` +Calculator App + | + +--- [input_module] -- User input parsing + +--- [calc_module] -- Arithmetic logic + +--- [display_module] -- Result formatting & display + +--- [history_module] -- History record management +``` + +**优势**: +- 降低复杂度:每个模块只关注一件事 +- 提高代码复用性:`calc_module` 可被其他项目引用 +- 便于团队协作开发:不同成员负责不同模块 +- 方便测试与调试:可单独对 `calc_module` 进行单元测试 + +### 3.3 封装 (Encapsulation) + +将模块的 **实现细节隐藏** 起来,仅 **暴露必要的接口** 给外部使用。 + +``` +┌──────────────────────────────┐ +│ [ Module ] │ +│ │ +│ ┌───────────────────┐ │ <- Public API +│ │ Interface │ │ +│ └────────┬──────────┘ │ +│ │ │ +│ ┌────────▼──────────┐ │ +│ │ Private │ │ <- Hidden Details +│ └───────────────────┘ │ +└──────────────────────────────┘ +``` + +**示例 — 汽车驾驶**: + +| 封装层 | 对外暴露(接口) | 隐藏细节 | +|--------|------------------|----------| +| 方向盘、油门、刹车 | 驾驶员可操作 | 引擎燃烧原理、变速箱齿轮比 | +| 函数 `sqrt(x)` | 输入 x,输出根号 x | 牛顿迭代法的具体计算过程 | + +```c +// math_utils.c -- 实现细节 +static double newton_sqrt(double n) // static: 仅内部可见性 +{ + // 牛顿迭代法的具体实现... 外部不能直接调用此函数 + double guess = n / 2.0; + + for (int i = 0; i < 100; i++) { + guess = (guess + n / guess) / 2.0; + } + + return guess; +} + +// math_utils.c -- 对外暴露的接口 +// 仅暴露必要的接口,隐藏实现细节 +// 例如:sqrt(9) = 3.0, sqrt(16) = 4.0 +double sqrt(double n) +{ + if (n < 0) return 0.0; // 内部校验逻辑,负数返回0 + + return newton_sqrt(n); +} +``` + +**原则**: +- 信息隐藏 (Information Hiding) +- 最小知识原则 (Principle of Least Knowledge) +- 高内聚、低耦合 + +--- + +## 本节小结 + +| 概念 | 核心要点 | +|------|----------| +| **编程** | 按照格式顺序编写代码,本质是对文件的操作 | +| **代码** | ASCII 文本文件,具有约定扩展名规范 | +| **编译器** | 将代码转换为可执行文件的工具,经历预处理→编译→汇编→链接 | +| **程序** | 编译后的可执行指令集 | +| **抽象** | 关注"做什么",忽略实现细节 | +| **模块化** | 分而治之,降低复杂度 | +| **封装** | 隐藏实现,暴露接口 | + +--- + +> **上一节**:无(起始章节) +> **下一节**:[→ 0.2 编程基础](./0.2%20Philosophy%20-%20Basic.md) diff --git a/Doc/0. Philosophy - Intro/0.2 Philosophy - Basic.md b/Doc/0. Philosophy - Intro/0.2 Philosophy - Basic.md new file mode 100644 index 0000000..678c4e4 --- /dev/null +++ b/Doc/0. Philosophy - Intro/0.2 Philosophy - Basic.md @@ -0,0 +1,464 @@ +--- +title: "编程基础" +subtitle: "Programming Philosophy - Basic Concepts" +version: "1.0" +category: "哲学篇 · 基础" +order: 0.2 +tags: [编程, 哲学, 基础, 编译, 规范] +prev: "./0.1%20Philosophy%20-%20Intro.md" +next: null +--- + +# 0.2 编程基础 + +> **本节导读**:掌握编程开发的规范体系,深入理解编译器的工作原理与完整编译流程。 +--- + +## 一、开发规范体系 + +> 规范是团队协作的基石,良好的编码习惯是程序员的基本素养。 + +### 1.1 项目规范 + + + +- [ ] 目录结构规范 +- [ ] 配置管理规范 +- [ ] 版本控制规范 + +**示例 — 推荐的 C 项目目录结构**: + +``` +my_project/ +|-- include/ # 头文件 (.h) +| +-- utils.h +|-- src/ # 源文件 (.c) +| +-- main.c +| +-- utils.c +|-- lib/ # 第三方库 +|-- build/ # 编译输出(不纳入版本控制) +|-- docs/ # 项目文档 ++-- README.md # 项目说明 +``` + +--- + +### 1.2 命名规范 + +- [ ] 变量命名规则 +- [ ] 函数命名规则 +- [ ] 文件命名规则 + +**示例 — 常见命名风格对比**: + +| 风格 | 示例 | 适用场景 | +|------|------|----------| +| `snake_case` | `user_name`, `file_path` | C 语言变量 / 函数 | +| `UPPER_SNAKE` | `MAX_BUFFER`, `PI` | 宏常量 / 枚举 | +| `camelCase` | `userName`, `filePath` | Java / JavaScript 变量 | +| `PascalCase` | `ClassName`, `StructName` | 类型 / 结构体名称 | + +```c +// Good: 符合 C 语言命名惯例 +int user_count = 0; +#define MAX_LENGTH 256 +void calculate_sum(int a, int b); + +// Bad: 混用风格、含义模糊 +int x = 0; // 含义不明 +#define ML 256 // 缩写无法理解 +void CS(int a, int B); // 函数名无意义 +``` +--- + +### 1.3 代码规范 + +- [ ] 缩进与格式 +- [ ] 注释规范 +- [ ] 错误处理规范 + +**示例 — 良好 vs 不良代码对比**: + +```c +// --- Bad: 无缩进、无注释、魔法数字 --- +int f(int r){return 3.14*r*r;} + +// --- +// Good: 规范缩进、有意义的命名、清晰注释 + +// Calculate the area of a circle with given radius. +// @param radius The radius of the circle (must be >= 0) +// @return The area of the circle +double calculate_circle_area(double radius) +{ + const double PI = 3.14159265; + + if (radius < 0) { + return 0.0; // Invalid input guard + } + + return PI * radius * radius; +} +``` +--- + +## 二、编译器概述 + +编译器是将人类可读的 **源代码** 转换为机器可执行的 **目标代码** 的程序。完整的编译过程包含四个主要阶段: + +| 阶段 | 工具 | 输入 | 输出 | 核心任务 | +|:----:|------|------|------|----------| +| ① 预处理 | Preprocessor | `.c` / `.h` | `.i` | 宏展开、头文件包含、条件编译 | +| ② 编译 | Compiler | `.i` | `.s` | 语法分析、语义分析、代码生成 | +| ③ 汇编 | Assembler | `.s` | `.o` | 汇编代码转机器码 | +| ④ 链接 | Linker | `.o` | `.exe` | 符号解析、地址重定位 | +--- + +## 三、编译流程详解 + +### 3.1 预处理阶段 (Preprocessing) + +> 预处理器的任务是对源文件进行文本层面的替换和处理,生成 **预处理后的源代码**。 + +#### 操作命令 + +```bash +# 查看预处理结果 +g++ -E main.c -o main.i +``` + +#### 预处理步骤详解 + +| 步序 | 操作 | 说明 | 示例 | +|:----:|------|------|------| +| 1 | 处理 `#include` | 包含指定的头文件内容 | `#include ` | +| 2 | 展开 `#define` | 进行宏替换 | `#define PI 3.14` | +| 3 | 条件编译 | 根据 #ifdef/#ifndef 等决定是否编译某段代码 | `#ifndef HEADER_H` | +| 4 | 删除注释 | 移除所有 `//` 和 `/* */` 注释 | — | + +> **TIP**:预处理后的 `.i` 文件通常非常大,因为包含了所有头文件的展开内容。 + +#### 预处理前后对比 + +**输入 (main.c)**: + +```c +#include + +#define MAX_SIZE 100 +#define SQUARE(x) ((x) * (x)) + +int main() +{ + int arr[MAX_SIZE]; + int val = SQUARE(5); + + printf("Value: %d\n", val); + + return 0; +} +``` + +**输出 (main.i — 部分截取)**: + +```c +// #include 被展开为上千行 stdio 的实际内容... +// 以下仅为宏展开部分: + +int main() +{ + int arr[100]; // MAX_SIZE -> 100 + int val = ((5) * (5)); // SQUARE(5) 宏展开 + + printf("Value: %d\n", val); // 注释保留(未删除前) + + return 0; +} +``` + +> **NOTE**:观察 `SQUARE(5)` 如何被替换为 `((5)*(5))` —— 这就是 **纯文本替换**,不做任何计算。 +--- + +### 3.2 编译阶段 (Compilation) + +> 编译器将预处理后的代码进行词法、语法、语义分析,最终生成 **汇编代码**。 + +#### 操作命令 + +```bash +# 生成汇编代码 +g++ -S main.i -o main.s +``` + +#### 编译步骤详解 + +``` +┌──────────────────────────┐ +│ Source Code (.i) │ +│ │ │ +│ ▼ │ +│ ┌────────────────────┐ │ +│ │ (1) Lexical │ ←│ Convert character stream into Token stream +│ │ Analysis │ │ int main() -> [int] [main] [(] [)] [{] ... +│ └────────┬───────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────┐ │ +│ │ (2) Syntax │ ←│ Build AST from Token stream +│ │ Analysis │ │ Check grammatical correctness +│ └────────┬───────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────┐ │ +│ │ (3) Semantic │ ←│ Type checking, scope analysis +│ │ Analysis │ │ Ensure semantic legality +│ └────────┬───────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────┐ │ +│ │ (4) IR Generation │ ←│ Generate platform-independent IR +│ │ │ │ e.g., Three-address code, SSA form +│ └────────┬───────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────┐ │ +│ │ (5) Code Optimizer │ ←│ Improve execution efficiency +│ │ │ │ e.g., Constant folding, DCE +│ └────────┬───────────┘ │ +│ │ │ +│ ▼ │ +│ ┌────────────────────┐ │ +│ │ (6) Target Code │ ←│ Generate assembly code (.s) +│ │ Generation │ │ Platform-specific instructions +│ └────────┬───────────┘ │ +│ │ │ +│ ▼ │ +│ Assembly Code (.s) │ +└──────────────────────────┘ +``` + +#### 词法分析示例 + +**源代码片段**: + +```c +int result = a + b * 2; +``` + +**词法分析输出 (Token 流)**: + +| Token | 类型 | 词面值 | +|:-----:|------|--------| +| 1 | KEYWORD | `int` | +| 2 | IDENTIFIER | `result` | +| 3 | OPERATOR | `=` | +| 4 | IDENTIFIER | `a` | +| 5 | OPERATOR | `+` | +| 6 | IDENTIFIER | `b` | +| 7 | OPERATOR | `*` | +| 8 | LITERAL | `2` | +| 9 | PUNCTUATION | `;` | + +> **NOTE**:词法分析器不关心语法是否正确,只负责将字符流切割为有意义的 Token。语法正确性由下一阶段的 **Parser** 判断。 + +#### 汇编代码示例 + +以下是一段 C 代码及其对应的 x86-64 汇编输出: + +**C 源码**: + +```c +int add(int x, int y) +{ + return x + y; +} +``` + +**生成的汇编代码 (`main.s` 截选)**: + +```asm +add: + pushq %rbp # Save frame pointer + movq %rsp, %rbp # Set up new stack frame + movl %edi, -4(%rbp) # Store param x at [rbp-4] + movl %esi, -8(%rbp) # Store param y at [rbp-8] + movl -4(%rbp), %eax # Load x into eax + movl -8(%rbp), %edx # Load y into edx + addl %edx, %eax # eax = eax + edx (core addition) + popq %rbp # Restore frame pointer + ret # Return (result in eax) +``` + +> **NOTE**:每一行汇编对应一条 **机器指令**,汇编器将人类可读的助记符(如 `movl`, `addl`)翻译为二进制机器码。 +--- + +### 3.3 汇编阶段 (Assembly) + +> 汇编器将汇编代码翻译为 **机器码**,生成 **可重定位目标文件**。 + +#### 操作命令 + +```bash +# 生成目标文件 +g++ -c main.s -o main.o +``` + +#### 目标文件结构 + +目标文件 (`.o`) 采用 **PE/COFF**(Portable Executable / Common Object File Format)格式,主要包含以下节区: + +| 节区 | 名称 | 存储内容 | +|:----:|------|----------| +| `.text` | 代码段 | 程序的机器指令 | +| `.data` | 数据段 | 已初始化的全局变量和静态变量 | +| `.bss` | BSS 段 | 未初始化的全局变量和静态变量(启动时清零)| +| `.rodata` | 只读数据段 | 字面常量(如字符串字面量)| +| `.symtab` | 符号表 | 函数和全局变量的符号信息 | +| `.strtab` | 字符串表 | 符号名称字符串 | +| `.rel.text` / `.rel.data` | 重定位表 | 需要重定位的信息 | +--- + +### 3.4 链接阶段 (Linking) + +> 链接器将多个目标文件及库文件合并,生成最终的 **可执行文件**。 + +#### 操作命令 + +```bash +# 链接单个目标文件 +g++ main.o -o main.exe + +# 链接多个目标文件 +g++ main.o utils.o -o app.exe +``` + +#### 链接器核心任务 + +##### ① 符号解析 (Symbol Resolution) + +将每个符号引用与其定义进行关联。未找到定义的符号称为 **未定义符号 (Undefined Symbol)**,将导致链接错误。 + +``` +main.o calls printf() + | + v +Linker looks up printf in libstdc++.a / libmingw32.a (MinGW-w64 runtime) + | + v +Found! -> Symbol resolved +``` + +##### ② 重定位 (Relocation) + +将目标文件中的相对地址转换为最终的可执行内存地址。 + +``` +重定位前 (目标文件中): + call printf @ 偏移量 0x10 + + ↓ 重定位 + +重定位后 (可执行文件中): + call printf @ 绝对地址 0x7ffc12345678 +``` + +##### ③ 节区合并 (Section Merging) + +将来自不同目标文件的同类节区合并为一个。 + +``` +┌────────────────────────────────────────────┐ +│ main.o .text ──┐ │ +│ ├→ Merge → Executable .text │ +│ utils.o .text ─┘ │ +│ │ +│ main.o .data ──┐ │ +│ ├→ Merge → Executable .data │ +│ utils.o .data ─┘ │ +└────────────────────────────────────────────┘ +``` + +#### 完整链接示例 + +假设有以下多文件项目结构: + +``` +project/ +|-- main.c # 主程序入口 +|-- utils.c # 工具函数 ++-- math.c # 数学函数 +``` + +**步骤演示**: + +```bash +# Step 1: 分别编译每个 .c 文件为 .o 目标文件(此时还未链接) +g++ -c main.c -o main.o # main.o 中引用了 add() 和 printf(),但不知道它们在哪里 +g++ -c utils.c -o utils.o # utils.o 定义了 add() +g++ -c math.c -o math.o # math.o 定义了 multiply() + +# Step 2: 链接器将所有 .o 合并 + 关联 C 标准库 +# 此时链接器会发现: +# - add() 在 utils.o 中定义 --> 符号解析成功 +# - multiply() 在 math.o 中定义 --> 符号解析成功 +# - printf() 在 msvcrt.dll (Windows 系统运行时) 中定义 --> 符号解析成功 +g++ main.o utils.o math.o -o app.exe + +# Step 3: 运行最终的可执行文件 +app.exe +``` + +**如果链接失败(符号未找到)**: + +```bash +g++ main.o -o app.exe +undefined reference to 'add' # 链接错误:缺少 utils.o +undefined reference to 'printf' # 链接错误:未链接运行时库 +collect2.exe: error: ld returned 1 exit status +``` + +> **NOTE**:**编译错误 (Compile Error)** 和 **链接错误 (Link Error)** 是不同的: +> - 编译错误:语法问题,如缺少分号、类型不匹配(编译阶段报错) +> - 链接错误:符号缺失,如函数声明了但未定义、忘记链接库文件(链接阶段报错) +--- + +## 四、完整编译流程速查 + +```mermaid +graph LR + A["源文件
(.c/.h)"] --> B["预处理器
Preprocessor"] + B --> C[".i 文件"] + C --> D["编译器
Compiler"] + D --> E[".s 文件
(汇编代码)"] + E --> F["汇编器
Assembler"] + F --> G[".o 文件
(目标文件)"] + G --> H["链接器
Linker"] + H --> I[".exe 文件
(可执行文件)"] +``` + +### 一键编译命令 + +```bash +# 完整编译过程(一步完成) +g++ main.c -o main.exe + +# 分步编译(便于调试) +g++ -E main.c -o main.i # 预处理 +g++ -S main.i -o main.s # 编译 +g++ -c main.s -o main.o # 汇编 +g++ main.o -o main.exe # 链接 +``` +--- + +## 本节小结 + +| 阶段 | 输入文件 | 输出文件 | 关键操作 | +|:----:|----------|----------|----------| +| 预处理 | `.c` | `.i` | 宏展开、头文件包含、去注释 | +| 编译 | `.i` | `.s` | 词法/语法/语义分析、代码优化 | +| 汇编 | `.s` | `.o` | 生成机器码和目标文件 | +| 链接 | `.o` | `.exe` | 符号解析、重定位、合并 | +--- + +> **上一节**:[← 0.1 编程哲学导论](./0.1%20Philosophy%20-%20Intro.md) +> **下一节**:待续