# c-learning **Repository Path**: PhiloKun/c-learning ## Basic Information - **Project Name**: c-learning - **Description**: C 语言完整知识体系:22 章中文笔记 70 个可一键编译运行的示例(C89→C23),全量通过 ASan/UBSan 验证 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-17 - **Last Updated**: 2026-11-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # C 语言完整知识体系 > 当前版本:v1.0.0(见 `version.txt`) > 从零到工程级 C(C89 → C99 → C11 → C17 → C23)的系统性学习仓库。 > **22 章**详细中文笔记 + **70 个可一键编译运行的示例**,与 [`cpp-learning`](https://github.com/PhiloKun/cpp-learning) 构成「C → 现代 C++」的完整路线。 ## 这个仓库和别的 C 教程有什么不同 绝大多数 C 教程只做到「能编译通过」。这个仓库多做三件事: | 承诺 | 怎么做到的 | |---|---| | **每一行代码都真的能跑** | 70 个示例覆盖 **65 个可执行程序**,全部通过 `cc -std=c17 -Wall -Wextra -Wpedantic -Werror` **零警告**编译 | | **每一个示例都真的运行过** | 全量运行验证:65 个程序全部退出码 0,输出符合预期 | | **没有一处隐藏的内存错误** | 全量 **AddressSanitizer + UndefinedBehaviorSanitizer** 验证,零报警 —— 包括内存池、哈希表、JSON 解析器这些重内存的章节 | 还有两个设计上的讲究: - **错误示范默认不编译**。想演示「越界会怎样」「use-after-free 长什么样」的代码,全部包在 `#ifdef DEMO_BUG` 里, 默认路径保持 ASan 干净;笔记正文会告诉你加 `-DDEMO_BUG` 编译后 ASan 会打印什么。想亲眼看到崩溃,自己开。 - **笔记里写的是实测数字,不是传说**。结构体成员换序后 `sizeof` 从 24 变 16、内存池比 `malloc/free` 快 8.8 倍、 哈希表插入 100 万条约 88 ns/次 —— 这些都是在 Apple clang 21 / arm64 上跑出来的,不是抄来的。 ## 本机环境 | 项目 | 值 | |---|---| | 编译器 | Apple clang 21.0.0(arm64-apple-darwin27) | | `cc` / `clang` | 均指向 clang;macOS 上 `gcc` / `g++` 是 clang 的别名,**不是真正的 GCC** | | 推荐标准 | `-std=c17`(本机 clang 支持到 C23,需要时用 `-std=c23`) | | cmake | 未安装 → 用仓库自带的 `build.sh` 一键编译 | | 调试器 | `lldb`(系统自带);`gdb` 需另行安装 | | Sanitizer | ASan / UBSan 可用;**TSan 可用,MSan 在 arm64 上不可用** | ## 快速开始 ```bash cd c-learning ./build.sh # 编译全部示例 → 输出到 build/ ./build.sh 08 # 只编译第 08 章 ./build.sh run 08 # 编译并运行第 08 章所有示例 ./build.sh run all # 编译并运行全部(共 65 个程序) ./build.sh asan 11 # 用 AddressSanitizer + UBSan 编译并运行第 11 章 ./build.sh clean # 清理 build/ ./build.sh -h # 帮助 ``` 单文件手动编译: ```bash cc -std=c17 -Wall -Wextra -Wpedantic -O2 \ "08-指针基础/pointer_basics.c" -o /tmp/demo && /tmp/demo ``` `build.sh` 的三条规则(值得看一眼,多文件示例依赖它): 1. 按「文件所在目录」分组;同目录下含 `main()` 的 `.c` 各自独立编译, 不含 `main()` 的 `.c` 作为辅助实现文件与之一起链接 —— 所以多文件示例放在一个子目录里。 2. 默认 `-std=c17`;文件前 20 行若出现 `// STD: c23` 注释,该文件改用 c23 编译。 3. 默认开启 `-Werror`(本仓库要求零警告)。临时放宽:`WERROR=0 ./build.sh`。 ## 学习路线 ``` 阶段一:语言地基(必须手写,不能只看) 01 环境搭建与编译模型 → 02 基本数据类型与字面量 → 03 作用域与存储类 04 运算符与表达式 → 05 流程控制 → 06 函数与参数传递 阶段二:C 的三根支柱 ★核心难点,值得反复读 07 数组与字符串 → 08 指针基础 ★ → 09 指针进阶 ★ → 10 结构体联合体位域 阶段三:内存与资源(C 的分水岭) 11 动态内存管理 ★ → 12 预处理器与宏 阶段四:底层与标准库 13 位操作与底层技巧 → 14 文件与标准IO → 15 标准库精讲 阶段五:工程化(从「会写 C」到「会用 C 做系统」) 16 用C实现面向对象 → 17 错误处理与防御式编程 → 18 泛型编程与回调 阶段六:收口 19 未定义行为与可移植性(避坑总纲,必读) 20 综合实战(动态数组 + 哈希表 + 迷你 JSON 解析器) 21 附录A · C 与 C++ 互操作 22 附录B · 调试与工具链 ``` 带 ★ 的章节是 C 与其他语言差异最大、最容易栽跟头的部分。 如果时间有限,**08 指针基础、09 指针进阶、11 动态内存管理**这三章必须精读。 ## 章节索引 | # | 章节 | 核心内容 | |---|---|---| | 01 | [环境搭建与编译模型](01-环境搭建与编译模型/README.md) | C 标准演进、翻译四阶段、翻译单元、声明/定义、链接属性、多文件与静态库、编译器选项、报错解读 | | 02 | [基本数据类型与字面量](02-基本数据类型与字面量/README.md) | 类型全景、宽度不固定、`char` 符号性、`sizeof`、字面量与后缀、IEEE 754、整型提升、隐式转换陷阱 | | 03 | [作用域与存储类](03-作用域与存储类/README.md) | 四种作用域、遮蔽、五种存储类、`static` 的三重含义、链接属性、`.bss` 与垃圾值、内存布局 | | 04 | [运算符与表达式](04-运算符与表达式/README.md) | 优先级全表、短路求值、位运算与逻辑运算的分界、移位 UB、序列点与求值顺序 | | 05 | [流程控制](05-流程控制/README.md) | 分支循环、真值判断、`switch` 穿透、**`goto` 统一错误清理**、循环边界、`unsigned` 倒计数死循环 | | 06 | [函数与参数传递](06-函数与参数传递/README.md) | 函数原型、值传递、栈帧、返回值陷阱、递归、`inline`、函数指针、可变参数 `va_list` | | 07 | [数组与字符串](07-数组与字符串/README.md) | 数组退化、数组≠指针、VLA、行主序与寻址、C 字符串约定、`string.h` 逐个拆解、安全替代方案 | | 08 | [指针基础](08-指针基础/README.md) | 内存模型、解引用、空/野/悬垂指针、指针算术、指针与数组的等价与不等价、`const` 四种组合、`void *` | | 09 | [指针进阶](09-指针进阶/README.md) | 多级指针、指针数组 vs 数组指针、函数指针与跳转表、回调与 `void *ctx`、`restrict`、右左法则 | | 10 | [结构体联合体位域](10-结构体联合体位域/README.md) | 浅拷贝、对齐与 padding 实测、`offsetof`、成员换序优化、匿名结构体、`union` 与类型双关、位域、柔性数组、`container_of` | | 11 | [动态内存管理](11-动态内存管理/README.md) | 栈 vs 堆、`malloc` 家族完整语义、`realloc` 陷阱、内存错误全谱、**ASan 定位实战**、内存池、动态二维数组 | | 12 | [预处理器与宏](12-预处理器与宏/README.md) | 预处理阶段、include guard、宏的四个经典陷阱、`do{}while(0)`、变参宏与 `__VA_OPT__`、X-Macro、条件编译、调试宏工具箱 | | 13 | [位操作与底层技巧](13-位操作与底层技巧/README.md) | 位掩码四件套、六个经典位技巧、内建函数、位图实现、字节序探测与转换、移位 UB 边界 | | 14 | [文件与标准IO](14-文件与标准IO/README.md) | 流与三个标准流、`fopen` 模式全解、安全读整行、二进制读写、`fseek`、缓冲机制、`feof` 的正确用法 | | 15 | [标准库精讲](15-标准库精讲/README.md) | `strtol` 完整校验、`qsort`/`bsearch`、`mem*` 与 `str*` 家族、`ctype` 的 UB 陷阱、`math`/`time`、`setjmp` | | 16 | [用C实现面向对象](16-用C实现面向对象/README.md) | 不透明指针封装、构造/析构约定、**手写虚函数表**、继承模拟、句柄表、接口结构体与鸭子类型 | | 17 | [错误处理与防御式编程](17-错误处理与防御式编程/README.md) | 错误码设计、`errno` 四条纪律、**`goto cleanup` 资源回卷**、断言/校验/日志的边界、整数溢出检测 | | 18 | [泛型编程与回调](18-泛型编程与回调/README.md) | `void *` + 元素大小 + 回调的通用容器、`qsort` 式接口设计、状态机与命令分发、`_Generic`、宏模板 | | 19 | [未定义行为与可移植性](19-未定义行为与可移植性/README.md) | UB/实现定义/未指定的三分法、**15+ 条 UB 清单**、严格别名、有符号溢出检测、对齐、可移植性实践 | | 20 | [综合实战](20-综合实战/README.md) | 动态数组 + 哈希表 + **迷你 JSON 解析器**(词法/递归下降/值树/dump 闭环)、自建单元测试、性能实测 | | 21 | [附录A · C与C++互操作](21-附录A-C与C++互操作/README.md) | 名称修饰实测、`extern "C"`、C 库给 C++ 用的完整实战、ABI 兼容、跨语言内存管理、迁移建议 | | 22 | [附录B · 调试与工具链](22-附录B-调试与工具链/README.md) | 警告体系、静态分析、Sanitizer 全家、**lldb 命令表与完整调试会话**、崩溃分析、二进制工具、Makefile 模板 | ## 示例代码一览 每个 `.c` 都是自包含的,文件头写明单文件编译命令。带 📁 的表示该章是多文件示例(放在子目录里)。 | 章 | 示例文件 | 演示内容 | |---|---|---| | 01 | `hello.c` `compilation_model.c` `preprocessor_basics.c` 📁`multifile/` | 最小程序、编译四阶段实证、预处理指令、头文件与多文件链接 | | 02 | `integer_types.c` `floating_point.c` `literals_and_conversions.c` | 类型宽度与 `sizeof`、IEEE 754 与精度损失、整型提升陷阱实测 | | 03 | `scope_rules.c` `storage_classes.c` 📁`linkage/` | 作用域与遮蔽、`static` 三重含义、跨文件 `extern` 共享 | | 04 | `operators_basics.c` `bitwise_operators.c` `evaluation_order.c` | 优先级陷阱、位运算与逻辑运算对比、求值顺序 | | 05 | `control_flow.c` `goto_and_cleanup.c` `switch_patterns.c` | 循环与真值判断、**三资源 `goto` 回卷**、`switch` 状态机 | | 06 | `function_basics.c` `function_pointers.c` `variadic_functions.c` | 值传递与栈帧、函数指针分发表、`va_list` 与 `vprintf` | | 07 | `arrays.c` `multidimensional_arrays.c` `c_strings.c` | 数组退化实证、行主序与寻址、安全字符串拷贝/拼接 | | 08 | `pointer_basics.c` `pointer_arithmetic.c` `const_pointers.c` | 指针基础、地址差/元素差/字节差、`const` 四种组合 | | 09 | `pointer_to_pointer.c` `function_pointer_table.c` `complex_declarations.c` | 多级指针、跳转表、`char *(*(*f)(int))(void)` 级声明拆解 | | 10 | `structs.c` `memory_layout.c` `unions_and_bitfields.c` | 结构体基础与浅拷贝、**偏移/padding 实测表**、`union` 与位域 | | 11 | `dynamic_memory.c` `memory_errors.c` `memory_pool.c` | `malloc` 家族与 `realloc` 正确写法、七类错误示范、自由链内存池 | | 12 | `macros.c` `xmacro.c` `conditional_compilation.c` `debug_config.h` | 宏陷阱实测、X-Macro 双向映射、编译期日志级别 | | 13 | `bit_tricks.c` `bitmask_and_flags.c` `endianness.c` | 二进制可视化位技巧、选项掩码、字节序探测与转换 | | 14 | `file_basics.c` `binary_io.c` `stdio_buffering.c` | 文本读写与安全读整行、二进制 IO、缓冲行为实测 | | 15 | `stdlib_demo.c` `string_functions.c` `time_and_math.c` | `strtol` 校验与 `qsort`/`bsearch`、`mem*` vs `str*`、时间格式化与计时 | | 16 | 📁`opaque_pointer/` `vtable.c` `handle_table.c` | 不透明指针三件套、**手写虚表多态**、带代数校验的句柄表 | | 17 | `errno_handling.c` `error_code_design.c` `defensive_programming.c` | `errno` 纪律、错误码与失败注入验证零泄漏、分层输入校验 | | 18 | `generic_container.c` `callbacks.c` `generic_selection.c` | 通用容器存多种类型、上下文回调/状态机/事件总线、`_Generic` 与宏模板 | | 19 | `undefined_behavior.c` `portability.c` `strict_aliasing.c` | UB 清单实证、实现定义行为探测、`memcpy` 破解严格别名 | | 20 | `dynamic_array.c` `hash_table.c` 📁`mini_json/` | 动态数组(含实测性能)、哈希表(FNV-1a + 链地址)、**迷你 JSON 解析器闭环** | | 21 | 📁`extern_c/{counter.h,counter.c,main_c.c}` `interop_rules.c` `cpp_caller.cpp` | C 库 + C/C++ 双端调用对照、C 代码进 C++ 编译的差异 | | 22 | `debug_demo.c` `log_and_assert.c` | 调试与优化级别差异、断言与 `NDEBUG` 行为对照 | > 第 21 章的 `cpp_caller.cpp` 是 C++ 源码,`build.sh` **不处理它**(`build.sh` 只管 `.c`)。 > 手动验证方式见该章笔记第 8 节:`cc -c` 编 C 目标文件 → `clang++` 链接。 ## 质量验证 本仓库的每一次内容变更都经过下面三道验证,可以自己复现: ```bash ./build.sh # 期望:编译成功 65 个,失败 0 个 ./build.sh run all # 期望:运行成功 65 个,运行失败 0 个 ./build.sh asan all # 期望:ASan + UBSan 全部干净,0 报警 ``` ## 与 `cpp-learning` 的关系 ``` c-learning(本仓库) cpp-learning ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ 01-15 语言与标准库 │ │ 01-15 语言与标准库 │ │ 16-18 工程化(OOP/错误/泛型) │ → │ 06-14 类/继承/模板/STL │ │ 19 UB 与可移植性(避坑) │ │ 19 最佳实践与陷阱 │ │ 20 综合实战(手写数据结构) │ │ 20 综合实战(线程池+日志) │ │ 21 附录A · C 与 C++ 互操作 ─┼──▶│ 21 对应:类与对象、RAII │ │ 22 附录B · 调试与工具链 │ │ (工具链完全复用) │ └──────────────────────────────┘ └──────────────────────────────┘ ``` 学完本仓库第 16 章(用 C 手写虚表、继承模拟)再去看 C++ 的 `virtual`,会有一眼看穿的感觉 —— 这正是把 C 学扎实的回报。第 21 章给出的迁移顺序(头文件保护 → `void *` 强转 → 逐步引入类与 STL)可以直接照做。 ## 推荐配套资源 - **规范**:[C11 标准草案 N1570](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)(免费、权威)、[C23 草案 N3096](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf) - **速查**:[cppreference C 部分](https://en.cppreference.com/w/c)(查函数语义的首选) - **书**:《C 程序设计语言》(K&R,薄但密度极高)、《C 陷阱与缺陷》(避坑)、《Expert C Programming》(底层洞察)、《21 世纪 C 语言》 - **必读文章**:[C 语言未定义行为清单](https://blog.regehr.org/archives/213)、[What Every C Programmer Should Know About Undefined Behavior](https://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html) - **动手看**:[Compiler Explorer](https://godbolt.org)(看 C 编译出的汇编,理解指针与优化的最好工具)、[Online C Compiler](https://godbolt.org/z/1)(快速验证小片段) - **练手**:[Exercism C track](https://exercism.org/tracks/c)、[LeetCode](https://leetcode.cn)(用纯 C 写,强制自己管内存)