第一章:初识计算机语言
1.1 什么是计算机语言?
- 计算机本质上就是一台按照指令工作的电子设备,如:
我们对计算机说:“计算两个数的和”,计算机其实并不能直接理解这句话。

- 计算机中的 CPU 最终能够执行的是
机器指令,如:10110000 01100001 ...。
提醒
机器指令:由二进制编码表示的指令,即:机器语言。

- 如果所有的程序都需要人类直接编写二进制指令,程序开发将会变得非常困难;于是,人类设计出了各种更加容易表达算法和逻辑的语言,即:计算机语言。
提醒
计算机语言 是 人与计算机 之间进行 信息表达 和 程序控制 的一套 形式化语言 。

- 对于我们学习编程而言,最重要的一类计算机语言就是编程语言,如:C、C++、Java 等。
提醒
掌握编程语言就能使用计算机解决实际问题,即:编程语言 → 表达算法和逻辑 → 计算机理解并执行 → 解决实际问题。

1.2 自然语言 VS 计算机语言
- 自然语言非常灵活,如:
帮我把这个文件打开。即使表达得不完全准确,人通常也能理解。
提醒
- ① 自然语言:灵活、宽松,更接近人类思维。
- ② 自然语言允许表达不完全正确,但人仍能理解并完成任务,这正体现了自然语言的灵活性和强大的人类理解能力。

- 计算机语言要求更加严格,如:C 语言中的
printf("Hello World\n");少一个;就会导致编译失败。
提醒
- ① 计算机语言:严格、精确,更接近机器思维。
- ② 计算机只能严格按照规则理解和执行程序,任何细微的错误都可能导致编译失败或运行出错。

自然语言和计算机语言的区别和联系,如下所示:
| 语言类别 | 特点 |
|---|---|
| 自然语言 | 💬 灵活多样,表达自由。 |
| 🤝 容错性高,不必完全正确。 | |
| 🧠 依赖上下文、经验和常识理解。 | |
| 👥 面向人类交流。 | |
| 计算机语言 | 📏 规则严格,必须完全正确。 |
| 🚫 容错性低,任何错误都可能导致失败。 | |
| 🔍 依赖编译器或解释器的严格检查。 | |
| ⚙️ 面向机器执行。 |
自然语言和计算机语言的共同目标,如下所示:
提醒
用清晰的方法表达思想,让对方(人或计算机)理解并完成任务!

1.3 为什么要学习计算机语言?
- 【问】现在的软件已经这么多了,为什么还需要学习编程语言?
- 【答】因为使用计算机和控制计算机,是两个不同的层次。
点我查看具体细节
- ① 普通用户 VS 程序员,如下所示:
| 用户类别 | 描述 |
|---|---|
| 普通用户 | 🌐 使用浏览器 |
| 📄 使用办公软件 | |
| 💬 使用微信 | |
| 🗄️ 使用数据库软件 | |
| ➕ …… | |
| 程序员 | 🛠️ 开发浏览器 |
| 💻 开发操作系统 | |
| 🗃️ 开发数据库 | |
| 🎮 开发游戏 | |
| 📱 开发应用软件 | |
| ➕ …… |
- ② 学习编程语言,就是学习如何把自己的想法转化为计算机能够执行的程序。
1.4 学习计算机语言到底在学习什么?
- 1️⃣ 从表面看,我们学习的是计算机语言的语法等,如:if、for、while、int、printf 等。

- 2️⃣ 其实,我们真正学习的是:问题 --> 分析 --> 抽象 --> 算法 --> 数据结构 --> 程序 --> 计算机执行。

- 3️⃣ 换言之,学习计算机语言不仅仅在学习语法等,更重要的是培养:逻辑思维,抽象能力、自动化能力。

1.5 计算机语言的发展简史
1.5.1 概述
- 计算机语言的发展,本质上在解决一个问题:
怎样让人更容易地控制计算机?。 - 计算机语言的发展,可以大致理解为:
机器语言 --> 汇编语言 --> 高级语言。
1.5.2 机器语言(相当于人类的石器时代)
- 1946 年 2 月 14 日,世界上第一台计算机
ENIAC诞生,使用的是最原始的穿透卡片。

- 上述使用的是
二进制代码表示的语言,和人类语言差别极大,被称为机器语言,如下所示:
0000,0000,000000010000 代表 LOAD A, 16
0000,0001,000000000001 代表 LOAD B, 1
0001,0001,000000010000 代表 STORE B, 162
3
机器语言的优缺点,如下所示:
| 优缺点 | 描述 |
|---|---|
| 优点 | ✅️ CPU 可直接执行,无需翻译。 |
| ✅️ 执行效率高,硬件控制精确。 | |
| 缺点 | ❌️ 难写:只能使用二进制指令。 |
| ❌️ 难读:代码含义不直观。 | |
| ❌️ 难调试:错误难以定位。 | |
| ❌️ 难维护:修改成本高。 | |
| ❌️ 不可移植:依赖具体 CPU 架构。 | |
| ❌️ 学习困难:需要熟悉 CPU 和硬件细节。 |
- 不同类型(CPU 架构,如:x86_64、arm 等)的处理器有不同的机器语言指令集,指令集架构(ISA)决定了机器语言的具体形式。
提醒
机器语言 与特定硬件架构紧密相关,机器语言程序几乎没有可移植性!!!

1.5.3 汇编语言(相当于人类的青铜&铁器时代)
汇编语言使用助记符代替二进制操作码,使程序更易于人类编写和理解。

- 为了避免直接记忆,人类开始给机器指令起名字,如下所示:
MOV AL, 5 ; # 10110000 00000101 ; 把数字 5 放入 AL 寄存器
ADD AL, 3 ; # 00000100 00000011 ; 把数字 3 加到 AL 寄存器中2
汇编语言的优缺点,如下所示:
| 优缺点 | 描述 |
|---|---|
| 优点 | ✅️ 比机器语言直观:使用 ADD 、 MOV 等助记符。 |
| ✅️ 执行效率高:可充分利用 CPU 指令。 | |
| ✅ 硬件控制精确:可直接操作寄存器和内存 | |
| ✅ 便于局部优化:适合优化关键代码。 | |
| 缺点 | ❌ 抽象层次低:复杂功能需要大量指令。 |
| ❌ 难开发:代码量大,容易出错。 | |
| ❌ 难调试和维护:需关注寄存器、内存等细节。 | |
| ❌ 学习困难:需要理解 CPU 和硬件原理。 | |
| ❌ 不可移植:依赖具体 CPU 架构。 |
汇编语言目前仍然应用于工业电子编程领域、软件的加密解密、计算机病毒分析等。
提醒
汇编语言 是 编程语言 的拓荒年代,它非常底层,直接和计算机硬件打交道,开发效率低,学习成本高。

1.5.4 高级语言
高级语言是一种接近于人们使用习惯的程序设计语言。高级语言允许程序员使用接近日常英语的指令来编写程序,程序中的符号和算式和日常使用的数学公式差不多,接近于自然语言和数学语言,容易被人们掌握。

- 高级语言
独立于计算机硬件,有一定的通用性;计算机不能直接识别和执行用高级语言编写的程序,需要使用编译器或解释器转换为机器语言,才能被计算机识别和执行。

高级语言的优缺点,如下所示:
| 优缺点 | 描述 |
|---|---|
| 优点 | ✅ 易读易写:语法更接近人类思维。 |
| ✅ 抽象能力强:支持函数、模块、对象等。 | |
| ✅ 开发效率高:少量代码即可实现复杂功能。 | |
| ✅ 易调试和维护:工具完善,结构清晰。 | |
| ✅ 可移植性强:通常可在不同平台运行。 | |
| 缺点 | ❌ 不能直接执行:需要编译器或解释器转换。 |
| ❌ 控制不够精细:难以直接操作底层硬件。 | |
| ❌ 存在额外开销:性能和资源占用可能较高。 | |
| ❌ 依赖运行环境:部分语言需要运行时或虚拟机。 |
- 目前普遍使用的
高级编程语言,有:C、C++、Java、Python、C#、JavaScript、Go 等。
提醒

1.6 编译型语言 VS 解释型语言
1.6.1 概述
- 高级编程语言出现之后,CPU 是不能直接理解的,还需要
翻译者,对应的典型方式有两种:
1.6.2 编译型语言 & 解释型语言
1.6.2.1 编译型语言
- 编译型语言的工作原理:在程序
运行之前,通过一个叫做编译器的工具,将源代码一次性全部翻译成目标机器能直接执行的机器码,如:qq.exe、wechat.exe 等。

- 编译型语言的执行过程:源代码(Hello.c)--> 编译器(GCC)--> 机器码(Hello.exe)--> CPU 直接运行。

- 编译型语言的典型代表语言:C、C++、Go、Rust、Swift 等。

- 编译型语言的优缺点,如下所示:
| 优缺点 | 描述 |
|---|---|
| 优点 | ✅️ 执行速度极快:因为程序运行时直接就是机器码,CPU 不需要再做任何翻译工作,性能最接近底层。 |
| ✅️ 不依赖运行环境:生成的可执行文件可以直接在目标机器上运行,不需要安装额外的语言环境。 | |
| 缺点 | ❌️ 跨平台性差:为 Windows (x86) 编译的程序,不能直接拿到 Mac (ARM) 上运行,即:换平台必须 重新编译。 |
| ❌️ 开发调试效率低:每次修改哪怕一行代码,都需要重新经历漫长的“编译”过程才能看到效果。 |
1.6.2.2 解释型语言
- 解释型语言的工作原理:在程序
运行时,通过一个叫做解释器的程序,逐行读取源代码,边翻译边执行,不生成独立的机器码文件。

- 解释型语言的执行过程:源代码(Hello.py)--> 解释器(Python)--> 边翻译边执行 --> CPU 直接运行。

- 解释型语言的典型代表语言:Python、JavaScript、Ruby、PHP、Bash 等。

- 解释型语言的优缺点,如下所示:
| 优缺点 | 描述 |
|---|---|
| 优点 | ✅️ 跨平台性极好:只要目标机器上安装了对应的解释器(如:Python 环境),同一份源代码就可以直接运行(“一次编写,到处运行”)。 |
| ✅️ 开发调试极快:改完代码直接运行,不需要等待编译,非常适合快速迭代和原型开发。 | |
| 缺点 | ❌️ 执行速度慢:因为每次运行都要“现场翻译”,比直接执行机器码慢得多(通常比编译型慢几倍到几十倍)。 |
| ❌️ 依赖运行环境:必须要求用户的电脑上安装了解释器,否则代码无法运行。 | |
| ❌️ 源码暴露:因为分发的是源代码,别人很容易看到你的核心逻辑(缺乏保密性)。 |
1.6.3 对比&总结
- 编译型语言 VS 解释型语言,如下所示:
| 维度 | 编译型语言 (C/C++) | 解释型语言 (Python/JS) |
|---|---|---|
| 翻译时机 | ⏱️ 运行 前,一次性翻译完 | 🔄 运行 时,逐行翻译 |
| 产物 | 📦 生成独立的机器码文件 ( .exe ) | 📤 不生成独立文件,直接输出结果 |
| 执行速度 | 🚀 极快(直接跑机器码) | 🐢 较慢(边翻译边执行) |
| 跨平台性 | ❌ 差(需针对不同平台重新编译) | ✅ 好(只要有解释器就能跑) |
| 开发效率 | ⚠️ 较低(修改后需重新编译) | 🚀 高(改完即跑) |
| 源码保密 | ✅ 高(别人只能看到机器码) | ❌ 低(直接分发源代码) |
1.6.4 现代视角的补充:界限正在模糊
- 随着技术发展,纯粹的
编译或解释已经不能完美满足需求,于是诞生了混合型:
点我查看 具体细节
| 混合型(中间态) | 描述 |
|---|---|
| 字节码 + 虚拟机(Java, C#) | 🔄 过程:Java 源代码先被编译成一种中间状态叫 “字节码”( .class 文件),然后由 Java 虚拟机(JVM)去解释执行或编译执行。 |
| ✨ 优势:完美结合了两者的优点。字节码是跨平台的,只要装了 JVM 就能跑(跨平台);JVM 内部又做了优化,速度比纯解释快。 | |
| JIT 即时编译 (现代 JavaScript, Python) | ⚡ 过程:解释器在运行时,如果发现某段代码被 频繁执行(热点代码),就会在内存中 临时把它编译成机器码 缓存起来,下次直接跑机器码。 |
| 🚀 优势:既保留了开发时的灵活性,又大幅提升了运行时的速度。 |

1.6.5 建议
- 如果追求
极致性能(游戏引擎、操作系统、高频交易),选编译型,如:C/C++、Rust。 - 如果追求
开发效率(数据分析、网站后端、AI),选解释型,如:Python、JS。 - 如果要做
大型企业级跨平台应用(微服务、大数据、中间件),选混合型,如:Java、C#。
第二章:C 语言的历史和辉煌
2.1 概述
- C 语言被称为现代计算机编程的“基石”与“母语”。从 20 世纪 70 年代诞生至今,它不仅奠定了现代软件工业的底座,更深刻地塑造了操作系统、编译器以及后续几乎所有主流编程语言的发展轨迹。

2.2 起源&诞生
- C 语言的诞生与 Unix 操作系统 的开发紧密关联,如下所示:
点我查看 具体细节
① 起源(1969 - 1970):肯·汤普森(Ken Thompson)在贝尔实验室使用汇编语言和 B 语言(基于 BCPL 开发)编写了最早的 Unix 系统。但由于汇编语言依赖特定硬件、而 B 语言缺乏数据类型,难以满足跨平台和性能需求。
② 突破(1972):丹尼斯·里奇(Dennis Ritchie)在 B 语言的基础上加入了强大的 类型系统 和 指针 机制,正是在 UNIX 的 DEC PDP-11 计算机上,C 语言正式宣告诞生。
③ 重写 Unix(1973):Unix 系统的大部分代码用 C 语言改写。这是历史上第一次使用高级语言来编写操作系统,直接赋予了 Unix 极强的可移植性。

2.3 C 语言发展的时间线
- C 语言的发展时间线,可以分为“
诞生→普及→标准化→现代化”四个阶段,如下所示:
点我查看 具体细节
| 时间 | 版本 / 事件 | 主要意义 | 阶段 |
|---|---|---|---|
| 1967 | BCPL | C 语言的重要祖先之一 | 诞生 |
| 1969~1970 | B 语言 | Ken Thompson 在 Bell Labs 开发,直接影响 C | |
| 1972 | C 语言诞生 | Dennis Ritchie 在 Bell Labs 设计 C | |
| 1973 | Unix 大量使用 C 重写 | C 与 Unix 相互促进,证明 C 可以用于操作系统开发 | |
| 1978 | K&R C | Kernighan 与 Ritchie 出版《The C Programming Language》,推动 C 普及 | 普及 |
| 1989 | C89 / ANSI C | 第一个正式 ANSI C 标准 | 标准化 |
| 1990 | C90 | C89 被 ISO 接纳为 国际标准 | |
| 1995 | C95 | 对 C90 的一次重要修订,增强国际化和字符支持 | |
| 1999 | C99 | 大规模现代化,引入 // 注释、inline、long long、变长数组等 | 现代化 |
| 2011 | C11 | 引入原子操作、线程支持、_Generic、_Static_assert 等 | |
| 2018 | C17 | 主要修复 C11 的缺陷,变化较小 | |
| 2023 / 2024 | C23 | 新一代 C 标准,进一步现代化;正式标准为 ISO/IEC 9899:2024 | |
| 未来 | C2y | WG14 正在继续开发 C23 之后的下一版 C 标准 |

2.4 C 语言的辉煌成就与统治力
- 即使在面向对象、函数式编程和脚本语言大行其道的今天,C 语言依然在底层与高并发场景中占据不可替代的位置。
点我查看 具体细节
- ① 现代软件基建的基底:
| 软件 | 描述 |
|---|---|
| 操作系统核心 | Linux 内核、Windows 内核、macOS/iOS (XNU)、Android 内核均主要由 C 语言编写。 |
| 嵌入式与物联网 | 从微控制器(MCU)、智能家居、汽车电子(AUTOSAR)到航天控制系统,C 语言凭极高的硬件控制能力和极低的运行时开销占据主导地位。 |
| 数据库引擎 | SQLite(全球部署量最大的数据库)、MySQL 内核、PostgreSQL 等基础存储组件均依赖 C 语言。 |
| 基础工具链与解释器 | Python(CPython 解释器)、Git、FFmpeg、GCC/Clang 编译器以及大量现代语言运行库(如 Node.js 底层的 libuv)均由 C 语言构建。 |
- ② 设计哲学的胜利:
| 特点 | 描述 |
|---|---|
| 极简与高效 | C 语言保持了贴近硬件的抽象(“高级汇编”),执行效率极高,内存占用极小。 |
| 对内存的绝对控制 | 通过指针和直接内存映射,程序员能够精确控制每一字节的内存使用。 |
| 极强的移植性 | 几乎所有微处理器架构(从 x86、ARM 到 RISC-V)都会在第一时间提供 C 语言编译器。 |
- ③ 对后续语言的深远影响:C 语言的语法(大括号分割代码块、表达式结构、控制流等)成为了现代编程语言的“通用语”。
| 深远影响 | 描述 |
|---|---|
| 直接继承与扩展 | C++、Objective-C。 |
| 语法派生 | Java、C#、JavaScript、PHP、Go、Rust 等均在语法层面大量借鉴了 C 语言。 |

2.5 总结
- C 语言的历史和辉煌,如下所示:

第三章:C 语言环境的搭建(🎯)
3.1 概述
- C 语言并没有像
Java或Rust那样“全家桶式”的统一标准工具链。
提醒
- Java:Maven 或 Gradle。
- Rust:Cargo 。
- C 语言的生态是由
编译器、构建工具和包管理器三层独立构成的,如下所示:
点我查看 具体细节
① 编译器:编译器负责将 C 语言源码(
.c)翻译为可执行的机器码。- GCC、Clang 与 LLVM 的关系:
编译器类别 描述 LLVM(编译器基础设施框架) 它不是一个直接拿来用的编译器,而是一个 模块化的编译器框架。 它定义了一套通用的中间代码(LLVM IR)。任何语言(C、C++、Rust、Swift)只要能翻译成 LLVM IR,就能直接复用 LLVM 强大的底层优化器和针对不同硬件(x86、ARM、RISC-V)的代码生成器。 Clang(编译器前端) 专门针对 C/C++/Objective-C 的 编译器前端。 它负责语法分析、语义检查,然后生成 LLVM IR,再交给后端 LLVM 去优化并生成最终二进制。 Clang 编译速度快、错误提示极其人性化,目前是 macOS (Xcode) 和 iOS 开发的默认编译器,在 Linux/Windows 上也广泛使用。 GCC(GNU Compiler Collection) Linux 世界的“基石”级编译器。历史悠久(始于 GNU 计划),支持几乎所有的硬件架构与操作系统。 GCC 是一个包含前端解析和后端优化的完整编译器套件。在 Linux 系统和嵌入式开发中占据绝对统治地位。 - 核心关系,如下所示:
核心关系 描述 特点 GCC 独立的一套经典编译器架构(GNU 体系) 两者在命令行参数上高度兼容。 Clang + LLVM 新一代模块化编译器架构(Clang 负责前段语法解析,LLVM 负责后段优化与生成代码)。 ② 构建工具:自动化编译流程(C 语言项目往往包含多个源码文件、头文件与外部库。直接手动敲
gcc file1.c file2.c -o app难以维护,因此需要构建工具)。
| 构建工具类别 | 描述 |
|---|---|
| Make(+ Makefile) | 最基础、最经典的构建工具。 |
通过编写 Makefile 脚本,定义文件依赖关系与编译命令,实现增量编译(仅重编译被修改的文件)。 | |
| CMake(元构建系统(Meta-Build System)) | 目前 C/C++ 跨平台开发的事实标准。 |
它不直接编译代码,而是读取 CMakeLists.txt 后 生成 适合当前平台的底层构建文件(在 Linux 上生成 Makefile,在 Windows 上生成 Visual Studio 工程,在 macOS 上生成 Xcode 工程)。 | |
| Meson | 现代、极速的元构建系统,使用 Python 编写,语法类似 Python,简洁清爽。 |
| 在 Linux 桌面生态(如 GNOME 社区)和许多现代化开源 C 项目中非常流行,搭配 Ninja(极速底层构建工具)使用体验极佳。 | |
| MSBuild / XCodeBuild | 分别是 Windows (Visual Studio) 和 Apple (Xcode) 平台的原生集成构建工具。 |
- ③ 包管理器:第三方库依赖管理(传统 C 语言没有标准包管理器,引用第三方库通常需要手动下载源码/预编译库、配置头文件路径(
-I)和链接库路径(-L/-l),现代 C 语言社区正在逐步普及包管理器)。
| 包管理器类别 | 描述 |
|---|---|
| vcpkg | 由微软主导开源的 C/C++ 包管理器,跨平台(Windows/Linux/macOS)支持极佳,能够与 CMake 深度无缝集成,非常适合获取常见的开源 C/C++ 库。 |
| Conan | 基于 Python 的现代分布式 C/C++ 包管理器,灵活且功能强大,多用于大型企业级项目的依赖版本管控。 |
| 系统级包管理器(Linux / MSYS2 / Homebrew) | 在 Linux 上直接使用 apt / pacman / dnf 安装 libxxx-dev 开发包;在 Windows 上使用 MSYS2 的 pacman 安装预编译好的 C 库,是传统且高频的使用方式。 |

3.2 Windows 搭建开发环境
3.2.1 概述
- 在 Windows 上选择 MSYS2 ,其是一套工具和库的集合,为我们提供一个易于使用的环境,用于构建、安装和运行原生 Windows 软件。
点我查看 具体细节
- ① MSYS2 = Unix 开发环境 + pacman 包管理 + MinGW-w64 + GCC / Clang + Windows 原生编译工具链。
- ② MSYS2 的整体结构,如下所示:
┌──────────────────────────────────────────────────────────┐
│ Windows 10 / 11 │
│ │
│ Kernel32.dll / UCRT / Win32 API / Windows Kernel │
└──────────────────────────▲───────────────────────────────┘
│
生成原生 Windows 程序
│
┌──────────────────────────┴───────────────────────────────┐
│ MSYS2 │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ MinGW-w64 环境 │ │
│ │ │ │
│ │ UCRT64 CLANG64 CLANGARM64 │ │
│ │ │ │ │ │ │
│ │ GCC Clang Clang │ │
│ │ │ │ │ │ │
│ │ x86-64 x86-64 ARM64 │ │
│ │ │ │ │ │ │
│ │ UCRT UCRT UCRT │ │
│ │ │ │ │ │ │
│ │ Windows 原生可执行程序 .exe / .dll │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ MSYS 环境 │ │
│ │ │ │
│ │ Bash / coreutils / grep / sed / awk / tar │ │
│ │ make / pacman / ssh / git ... │ │
│ │ │ │ │
│ │ MSYS2 Runtime │ │
│ │ (基于 Cygwin) │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ pacman │
│ 统一管理软件包 │
└──────────────────────────────────────────────────────────┘2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- ③ MSYS2 当前几个主要架构,如下所示:
| 环境 | CPU | 编译器 | C 运行库 | C++ 库 | 目录 | 是否推荐 |
|---|---|---|---|---|---|---|
| MSYS | x86-64 | GCC | Cygwin | libstdc++ | /usr | ❌️ |
| UCRT64 | x86-64 | GCC | UCRT | libstdc++ | /ucrt64 | ✅️ |
| CLANG64 | x86-64 | Clang/LLVM | UCRT | libc++ | /clang64 | ✅️ |
| CLANGARM64 | ARM64 | Clang/LLVM | UCRT | libc++ | /clangarm64 | ❌️ |

3.2.2 安装
3.2.2.1 概述
安装分为手动安装和自动安装(命令行)两种。
3.2.2.2 手动版
- ① 鼠标双击安装包,如下所示:

- ② 点击
Next,如下所示:

- ③ 指定安装目录,并点击
Next,如下所示:
建议
尽量选择默认文件夹!!!

- ④ 点击
Next,如下所示:

- ⑤ 点击
Next,如下所示:

- ⑥ 点击
Finish,如下所示:

- ⑦ 安装相关工具,如下所示:
# 替换清华镜像源(可选)
sed -i \
"s#https\?://mirror.msys2.org/#https://mirrors.tuna.tsinghua.edu.cn/msys2/#g" \
/etc/pacman.d/mirrorlist*
# 安装相关工具链
pacman -Syu --noconfirm # 更新包管理器
pacman -Sy base-devel --noconfirm # 安装开发工具包
# 安装 UCRT 编译工具链及构建工具
pacman -Syu --noconfirm \
mingw-w64-ucrt-x86_64-toolchain \
mingw-w64-ucrt-x86_64-meson \
mingw-w64-ucrt-x86_64-cmake
# 安装 Clang 编译工具链及构建工具
pacman -Syu --noconfirm \
mingw-w64-clang-x86_64-toolchain \
mingw-w64-clang-x86_64-meson \
mingw-w64-clang-x86_64-cmake2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

3.2.2.3 自动版
- ① 打开 powershell,如下所示:

- ② 执行安装,如下所示:
winget install --id MSYS2.MSYS2 -e --source winget
- ③ 安装相关工具,如下所示:
# 替换清华镜像源(可选)
sed -i \
"s#https\?://mirror.msys2.org/#https://mirrors.tuna.tsinghua.edu.cn/msys2/#g" \
/etc/pacman.d/mirrorlist*
# 安装相关工具链
pacman -Syu --noconfirm # 更新包管理器
pacman -Sy base-devel --noconfirm # 安装开发工具包
# 安装 UCRT 编译工具链及构建工具
pacman -Syu --noconfirm \
mingw-w64-ucrt-x86_64-toolchain \
mingw-w64-ucrt-x86_64-meson \
mingw-w64-ucrt-x86_64-cmake \
mingw-w64-ucrt-x86_64-bear \
mingw-w64-ucrt-x86_64-cunit
# 安装 Clang 编译工具链及构建工具
pacman -Syu --noconfirm \
mingw-w64-clang-x86_64-toolchain \
mingw-w64-clang-x86_64-meson \
mingw-w64-clang-x86_64-cmake \
mingw-w64-clang-x86_64-bear \
mingw-w64-clang-x86_64-cunit2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

3.2.3 配置
3.2.3.1 概述
- 安装完毕之后,需要配置 PATH 环境变量,以便系统可以识别 CLANG。
CLANG_HOME=C:\msys64\clang64
PATH=%CLANG_HOME%\bin;%PATH%2
- PATH 环境变量分为
针对当前用户以及针对管理员两种,如下所示:
| PATH 环境变量分类 | 描述 | 备注 |
|---|---|---|
| 针对当前用户 | 当前用户有效 | 配置完成后,需要重新打开 PowerShell 窗口才能使新配置在终端中生效。 |
| 针对管理员 | 所有用户生效 |
3.2.3.2 手动版
- ① 打开
设置-->系统-->高级系统设置-->环境变量,如下所示:

- ② 在
系统变量中配置PATH环境变量,如下所示:

3.2.3.3 自动版
- 格式:
# 临时生效(仅对当前 PowerShell 窗口有效)
$env:CLANG_HOME = "C:\msys64\clang64"
$env:PATH = $env:PATH + ";$env:CLANG_HOME\bin"
# 验证配置
# 1. 查看 CLANG_HOME
$env:CLANG_HOME
# 2. 检查 clang 是否可被识别
clang --version2
3
4
5
6
7
8
9
10
11
# 永久生效(针对当前用户)
# 1. 设置用户级别的 CLANG_HOME
[Environment]::SetEnvironmentVariable("CLANG_HOME", "C:\msys64\clang64", "User")
# 2. 将 %CLANG_HOME%\bin 追加到用户 PATH 的末尾
$oldUserPath = [Environment]::GetEnvironmentVariable("PATH", "User")
if ($oldUserPath -notlike "*%CLANG_HOME%\bin*") {
# 注意:确保旧 PATH 末尾有分号分隔符
$separator = if ($oldUserPath.EndsWith(";")) { "" } else { ";" }
$newUserPath = $oldUserPath + $separator + "%CLANG_HOME%\bin"
[Environment]::SetEnvironmentVariable("PATH", $newUserPath, "User")
}
# 验证配置
# 1. 查看 CLANG_HOME
$env:CLANG_HOME
# 2. 检查 clang 是否可被识别
clang --version2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 系统级永久生效(需要管理员权限),即:以管理员身份运行 PowerShell
# 1. 设置系统级别的 CLANG_HOME
[Environment]::SetEnvironmentVariable("CLANG_HOME", "C:\msys64\clang64", "Machine")
# 2. 将 %CLANG_HOME%\bin 追加到系统 PATH 的末尾
$oldSystemPath = [Environment]::GetEnvironmentVariable("PATH", "Machine")
if ($oldSystemPath -notlike "*%CLANG_HOME%\bin*") {
$separator = if ($oldSystemPath.EndsWith(";")) { "" } else { ";" }
$newSystemPath = $oldSystemPath + $separator + "%CLANG_HOME%\bin"
[Environment]::SetEnvironmentVariable("PATH", $newSystemPath, "Machine")
}
# 验证配置
# 1. 查看 CLANG_HOME
$env:CLANG_HOME
# 2. 检查 clang 是否可被识别
clang --version2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 示例:系统级永久生效(以管理员身份运行 PowerShell)
# 1. 设置系统级别的 CLANG_HOME
[Environment]::SetEnvironmentVariable("CLANG_HOME", "C:\msys64\clang64", "Machine")
# 2. 将 %CLANG_HOME%\bin 追加到系统 PATH 的末尾
$oldSystemPath = [Environment]::GetEnvironmentVariable("PATH", "Machine")
if ($oldSystemPath -notlike "*%CLANG_HOME%\bin*") {
$separator = if ($oldSystemPath.EndsWith(";")) { "" } else { ";" }
$newSystemPath = $oldSystemPath + $separator + "%CLANG_HOME%\bin"
[Environment]::SetEnvironmentVariable("PATH", $newSystemPath, "Machine")
}2
3
4
5
6
7
8
9
10

- 示例:验证配置(重新打开 PowerShell 窗口)
# 1. 查看 CLANG_HOME
$env:CLANG_HOME
# 2. 检查 clang 是否可被识别
clang --version2
3
4
5

3.3 WSL2 搭建开发环境
3.3.1 概述
- 在 Linux 中,C/C++ 也有上述的工具链,本次以 WSL2 来进行演示。
3.3.2 WSL2 安装 C/C++ 工具链
WSL2 可以安装的 Linux 非常多,本次以 AlmaLinux-9 和 Ubuntu 24.04 为例进行演示。
示例:AlmaLinux-9
# 1. 更新系统并安装 dnf 核心扩展插件
sudo dnf -y update
sudo dnf install -y dnf-plugins-core epel-release
# 2. 启用 CRB (CodeReady Linux Builder) 仓库 (获取 ninja-build 等工具)
sudo dnf config-manager --set-enabled crb
# 3. 安装基础 C/C++ 开发环境与构建工具
sudo dnf groupinstall "Development Tools" -y
sudo dnf install -y \
gcc \
gcc-c++ \
gdb \
make \
cmake \
ninja-build \
pkgconf-pkg-config \
binutils \
git \
glibc-devel \
meson \
bear \
CUnit-devel
# 4. 安装 Clang / LLVM 工具链 (clangd 包含在 clang-tools-extra 中)
sudo dnf install -y \
clang \
clang-tools-extra \
llvm \
lldb
# 5. 开启 debuginfo 仓库并安装 glibc 调试信息及源码
# --enablerepo 参数确保能调取 AppStream-debug 和 BaseOS-debug 源
sudo dnf debuginfo-install -y \
--enablerepo=*debug* \
glibc
sudo dnf install -y \
--enablerepo=*debug* \
glibc-debugsource2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

- 示例:Ubuntu 24.04
# 1. 开启 deb-src 源码源
sudo sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources
# 2. 更新系统软件包列表
sudo apt update && sudo apt upgrade -y
# 3. 安装基础 C/C++ 开发环境与构建工具
sudo apt install -y \
build-essential \
gdb \
debuginfod \
cmake \
ninja-build \
pkg-config \
binutils \
git \
libc6-dev \
dpkg-dev \
meson \
bear \
libcunit1-dev
# 4. 安装 Clang / LLVM 工具链
sudo apt install -y \
clang \
clangd \
clang-tools \
llvm \
lldb
# 5. 安装 glibc 调试符号包
sudo apt install -y libc6-dbg
# 6. 静默下载 glibc 源码(消除 root 沙盒警告)
cd /usr/src
apt source glibc -o APT::Sandbox::User=root2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

第四章:C 语言入门程序(🎯)
4.1 概述
- 学习任何编程语言,输出 "Hello World" 都是编程语言的第一课,主要有以下几个核心原因:
点我查看 具体细节
| 输出 "Hello World" 的核心原因 | 描述 |
|---|---|
| 1️⃣ 验证最基础的开发环境 | 编译/运行链路:打印一句话看似简单,但它能直接验证代码编辑器、编译器(或解释器)以及运行环境是否正确安装和配置。 |
| 极低排错成本:语法只有一两行。如果运行报错,原因只可能出在环境安装或最基础的语法结构上,而不是复杂的业务逻辑。 | |
| 2️⃣ 建立极简的反馈闭环 | 降低心理门槛: 对于零基础新手来说,第一次在屏幕上看到自己亲手敲出的代码产生预期结果,能建立极强的心理正反馈。 |
| 理解基本输入输出(I/O): 它向开发者展示了该语言处理“将数据传递给控制台/终端”的最简语法格式。 | |
| 3️⃣ 展现语言的“设计基因”:不同语言输出 "Hello World" 的复杂度,直接反映了该语言的设计理念与语法风格。 | Python(极致简洁): |
C 语言(需处理头文件与入口函数): | |
Java(严格的面向对象与类封装): | |
| 4️⃣ 历史起源 | 这个传统最早由 C 语言之父 Brian Kernighan 于 1972 年在贝尔实验室的 B 语言内部文档中提出。 |
| 随后在 1978 年出版的经典著作《C 程序设计语言》(The C Programming Language)中被正式沿用,并迅速推广至整个计算机科学界。 |

4.2 Hello World
- 格式:
#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}2
3
4
5
6
7
8
- 示例:
#include <stdio.h>
int main() {
printf("Hello World\n");
return 0;
}2
3
4
5
6
7
8

4.3 C 语言中的注释
4.3.1 概述
- 在 C 语言中,注释是用于向代码添加说明或解释,它们不会被程序编译执行。
- 在 C 语言中,提供了两种类型的注释:
单行注释和多行注释。
4.3.2 单行注释
- 格式:
// 单行注释提醒
单行注释用于注释掉一行代码,// 后面的所有内容都视为注释。
- 示例:
#include <stdio.h>
int main() {
// 这是一个单行注释
int age = 18; // 这是行尾注释
printf("Hello World\n");
return 0;
}2
3
4
5
6
7
8
9
10
11
4.3.3 多行注释
- 语法:
/*
多行注释
多行注释
...
*/2
3
4
5
提醒
- ① 多行注释用于注释掉多行代码。
- ② 多行注释的语法是从
/*开始,到*/结束,注释内容位于这两个符号之间。
- 示例:
#include <stdio.h>
int main() {
/*
这是一个多行注释
可以注释多行内容
*/
printf("Hello World\n");
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
第五章:CLion(🎯)
5.1 概述
- 常见的 C/C++ IDE,如下所示:
点我查看 具体细节
| 工具 | 类型 | 平台 | 特点 | 推荐度 |
|---|---|---|---|---|
| CLion | 完整 IDE | Windows / Linux / macOS | C/C++ 专业 IDE,代码分析、重构、CMake/Meson、GCC/Clang/MSVC、WSL 支持很好 | ⭐⭐⭐⭐⭐ |
| Visual Studio | 完整 IDE | Windows | 微软官方,MSVC 体验最好,调试器非常强,Windows C/C++ 首选之一 | ⭐⭐⭐⭐⭐ |
| Qt Creator | 完整 IDE | Windows / Linux / macOS | 原生 C++/Qt 支持很好,也适合普通 C/C++ 与嵌入式 | ⭐⭐⭐⭐ |
| Eclipse CDT | 完整 IDE | Windows / Linux / macOS | Eclipse 的 C/C++ 开发套件,传统大型项目较多 | ⭐⭐⭐ |
| Code::Blocks | 完整 IDE | Windows / Linux / macOS | 免费、简单、轻量,适合教学和小项目 | ⭐⭐⭐ |
| Xcode | 完整 IDE | macOS | Apple 官方 IDE,支持 Clang 和 C/C++ | ⭐⭐⭐ |
| KDevelop | 完整 IDE | Linux 为主 | KDE 生态,C/C++ 支持不错 | ⭐⭐⭐ |
| VS Code | 编辑器 + 插件 | Windows / Linux / macOS | 非传统完整 IDE,但装 C/C++/clangd/CMake 插件后很好用 | ⭐⭐⭐⭐⭐ |

- IDE 不是编译器,其是用来“写代码 + 编译 + 运行 + 调试 + 管理项目”的一体化开发软件。
点我查看 具体细节
- 假设我们廨 C/C++ 的时候,如果不使用 IDE,可能需要分别使用如下的工具:
文本编辑器 → 写代码
GCC / Clang → 编译
GDB / LLDB → 调试
CMake / Meson → 构建项目
终端 → 运行程序
Git → 版本管理2
3
4
5
6
- 但是,IDE 会将这些东西整合到一个软件中,如下所示:
IDE
│
┌──────────┼──────────┐
↓ ↓ ↓
代码编辑 编译构建 调试
│ │ │
代码补全 GCC/Clang GDB/LLDB
│
├── 项目管理
├── Git
├── 终端
└── 重构/代码检查2
3
4
5
6
7
8
9
10
11
12

- 如果刚开始学习,那就根据平台选择最适合自己的 IDE,如下所示:
点我查看 具体细节
| 平台 | IDE | 原因 | 推荐度 |
|---|---|---|---|
| Windows | CLion | 想省心、现代化 | ⭐⭐⭐⭐⭐ |
| Visual Studio | Windows 原生开发 | ⭐⭐⭐⭐⭐ | |
| VS Code | 想自己搭工具链 | ⭐⭐⭐⭐⭐ | |
| Linux / WSL | CLion | 完整 IDE | ⭐⭐⭐⭐⭐ |
| VS Code | 轻量 | ⭐⭐⭐⭐⭐ | |
| Qt Creator | Qt GUI | ⭐⭐⭐⭐ | |
| macOS | CLion | 通用 C/C++ | ⭐⭐⭐⭐⭐ |
| Xcode | Apple 开发 | ⭐⭐⭐⭐ | |
| VS Code | 轻量 | ⭐⭐⭐⭐⭐ |

5.2 CLion 是什么?
- CLion 是目前非常典型的专业 C/C++ IDE,明确支持 GCC、Clang、MSVC,以及 CMake、Makefiles、Bazel、Meson 等工具链和构建系统,并且目前对于非商业用途免费。

5.3 安装&配置
5.3.1 安装
5.3.1.1 手动版
- ① 鼠标双击安装包,如下所示:

- ② 点击
下一步,如下所示:

- ③ 指定安装目录,并点击
下一步,如下所示:

- ④ 点击
下一步,如下所示:

- ⑤ 点击
安装,如下所示:

- ⑥ 点击
完成,如下所示:

3.3.3.2 自动版
- ① 打开 powershell,如下所示:

- ② 执行安装,如下所示:
winget install --id JetBrains.CLion -e --source winget
5.3.2 通用配置
5.3.2.1 概述
- CLion 的
全局配置在自定义-->所有设置中,如下所示:
提醒
所谓的 全局配置 ,一旦修改将对所有项目生效!!!

5.3.2.2 外观与行为
- 外观与行为 --> 外观 --> 无障碍功能 --> 使用自定义字体(MiSans),如下所示:

- 外观与行为 --> 外观 --> UI 选项,如下所示:
提醒
- 紧凑模式:√ 。
- 主菜单:显示在主工具栏上方。

- 外观与行为 --> 系统设置,如下所示:
提醒
- 退出 IDE 之前确认:× 。
- 启动时重新打开项目:× 。
- 如果 IDE 空闲则保存文件 15 秒:√ 。

- 外观与行为 --> 系统设置 --> 更新,如下所示:
提醒
自动更新插件:√ 。

5.3.2.3 编辑器
- 编辑器 --> 常规 --> 代码补全 --> 弹出窗口,如下所示:
提醒
- 区分大小写:× 。
- 通过按空格、点或其他上下文相关键插入选定建议:√ 。
- import 条目的行为:始终带有选项的菜单。
- 显示函数签名:√ 。
- 形参信息:
| 形参信息子选项 | 是否选中 |
|---|---|
| 补全时显示形参名称提示 | √ |
| 显示完整的方法签名 | √ |

- 编辑器 --> 常规 --> 外观,如下所示:
提醒
显示方法分隔符:√ 。

- 编辑器 --> 字体,如下所示:
提醒
- 字体:Fira Code。
scoop bucket add nerd-fonts
scoop install firacode2
- 板式设置:
| 板式设置 | 选择 |
|---|---|
| 主要粗细 | Bold |
| 加粗 | Bold |
| 回滚字体 | SimHei |

- 编辑器 --> 检查,如下所示:
提醒
C/C++ :√ 。

- 编辑器 --> 检查,如下所示:
提醒
- 形参名称:√ 。
- 类型:√ 。
- 值:√ 。

5.3.2.4 版本控制
- 版本控制 --> Git,如下所示:
提醒
需要事先安装好 Git!!!

5.3.2.5 构建、执行、部署
- 构建、执行、部署 --> 工具链,如下所示:

5.3.2.6 工具
- 工具 --> 保存时的操作,如下所示:

5.4 创建项目
- 项目 --> 新建项目,如下所示:

- 修改 CLion 的虚拟机配置:
-Xmx2048m
-Dfile.encoding=UTF-8
-Dconsole.encoding=UTF-82
3

- 修改 main.c 的内容,如下所示:
#include <stdio.h>
int main(void) {
// 避免调试或交互输入时内容滞留在缓冲区。
if (setvbuf(stdout, nullptr, _IONBF, 0) != 0) {
(void)fputs("warning: failed to disable stdout buffering\n", stderr);
}
// Windows 使用 UTF-8 locale 名称;其他平台采用用户环境中的 locale。
#ifdef _WIN32
const char *locale_name = ".UTF-8";
#else
const char *locale_name = "";
#endif
if (setlocale(LC_ALL, locale_name) == nullptr) {
(void)fputs("warning: failed to configure the user locale\n", stderr);
}
printf("你好,世界!\n");
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

第六章:解读 HelloWorld(🎯)
6.1 概述
- 对于 C 语言入门程序,虽然只有几行;但是,几乎包含了一个 C 程序最核心的几个概念:
头文件、函数、程序入口、函数调用、字符串、标准输出、转义字符以及返回值等。
#include <stdio.h> // 头文件
int main() { // 程序的入口
// 标准输出,即:将 HelloWorld\n 输出到控制台,并换行
// 调用 C 标准库提供的 printf() 函数
printf("Hello World\n");
return 0; // 返回值
}2
3
4
5
6
7
8
9
10
- 其实,对于上述的代码,我们可以这么理解:
告诉编译器:我要使用 printf
↓
程序从 main 开始执行
↓
调用 printf 输出 Hello World
↓
return 0 告诉操作系统:程序正常结束2
3
4
5
6
7
6.2 头文件和标准库
6.2.1 概述
- 我们要想使用
printf()函数,必须在 C 程序中首行中导入stdio.h头文件,如下所示:
#include <stdio.h>- 我们可以将其进行拆分,如下所示:
# include <stdio.h>
│ │ │
│ │ └─ 标准输入输出头文件
│ └─ 包含
└─ 预处理指令2
3
4
5
- 其中,
stdio.h中的stdio是standard input output的缩写,即:标准输入输出。
提醒
stdio.h 中声明了很多标准输入输出函数,而 printf() 函数仅仅是其中的一种而已。
...
// 标准输出(声明)
int __cdecl printf(const char * __restrict__ _Format,...);
// 标准输入(声明)
int __cdecl scanf(const char * __restrict__ _Format,...);
...2
3
4
5
6
7
8

- 因为我们需要使用
printf()函数,所以我们需要将stdio.h头文件包含进来,如下所示:
// 头文件
#include <stdio.h>
int main() {
// 标准输出
printf("Hello World\n");
return 0;
}2
3
4
5
6
7
8
9
10
stdio.h文件中的printf()是没有具体实现的,真正的函数体是在标准库中,如下所示:
提醒
- ① 在 C 语言中,头文件 和 标准库 是两个常被一起提及但概念不同的核心要素。
- ② 简单来说:标准库是“工具箱本身”,而头文件是“使用说明书兼工具入口”。
// 头文件中只有函数声明
#include <stdio.h>
int main() {
// 标准输出
// 演示如何在标准库中找到函数体!!!
printf("Hello World\n");
return 0;
}2
3
4
5
6
7
8
9
10
11

6.2.2 头文件
头文件是以.h结尾的文本文件,它的主要作用是声明(告诉编译器有哪些函数、变量或数据类型可以使用)。
点我查看 具体细节
- 1️⃣
核心作用:编译器在处理.c代码时,逐行向上向下检查。当使用printf()时,如果编译器此前没见过这个函数的定义,就会报错“找不到该函数”。引入头文件就是为了提前告诉编译器:“printf是一个合法的函数,它接受什么参数、返回什么类型,请准许通过。” - 2️⃣
工作机制:当在代码顶部写#include <stdio.h>时,预处理器会把stdio.h文件的全部文本原封不动地“复制粘贴”到代码的开头。

6.2.3 标准库
标准库是 C 语言官方为我们提前写好、编译好的基础功能代码集合。
点我查看 具体细节
- 1️⃣
为什么存在:如果每次写程序都要从零编写“如何向屏幕输出字符”、“如何计算平方根”、“如何分配内存”,开发效率会极低。C 语言官方将这些最常用的底层功能封装好,作为语言的一部分随编译器一起提供给我们。 - 2️⃣
包含内容,如下所示:- 输入输出:如打印文本 (
printf)、读取键盘输入 (scanf)。 - 数学计算:如求绝对值 (
abs)、三角函数 (sin)、开方 (sqrt)。 - 字符串操作:如计算字符串长度 (
strlen)、拼接字符串 (strcat)。 - 内存管理:如动态申请内存 (
malloc)、释放内存 (free)。
- 输入输出:如打印文本 (
- 3️⃣
常见的 C 语言头文件及其功能和常用函数、宏等,如下所示:
| 头文件 | 功能说明 | 常用函数和宏 |
|---|---|---|
| stdio.h | 标准输入输出库 | printf, scanf, fprintf,fscanf,fopen, fclose,fgets, fputs |
| stdlib.h | 标准库,提供内存分配、程序控制、类型转换、随机数生成等功能 | malloc, free, exit, atoi, atof,rand,srand |
| string.h | 字符串处理库 | strlen, strcpy, strncpy, strcat, strcmp,strstr, memset, memcpy |
| math.h | 数学库 | sin, cos, tan, exp, log, sqrt, pow |
| time.h | 时间和日期库 | time, clock, difftime, mktime, strftime, localtime,gmtime |
| ctype.h | 字符处理库 | isalnum, isalpha, isdigit, islower, isupper, tolower, toupper |
| stdbool.h | 布尔类型库 | bool, true, false |
| assert.h | 断言库 | assert |

6.2.4 预处理命令
#include命令的作用是将指定文件的内容插入到包含该命令的源文件中。示例:用于包含标准库头文件或系统头文件
// 编译器将在系统的标准头文件目录中查找文件。
#include <filename>2
- 示例:用于包含用户自定义的头文件
// 编译器首先在当前目录中查找文件,如果未找到,再在标准头文件目录中查找。
#include "filename"2
6.3 main 函数
- 在 C 语言里,
main函数可以理解为:程序的主入口函数 ,即:无论 C 语言程序写了几千行代码、分散在多少个文件中,操作系统在启动这个程序时,永远只会寻找并执行main函数里的代码。
点我查看 具体细节
- 1️⃣
main 函数的四大核心特性,如下所示:
| main 函数的四大核心特性 | 描述 |
|---|---|
| 唯一的入口 | 一个可执行的 C 程序中,有且只能有一个 main 函数。 |
| 自动调用 | 不需要在代码中手动去调用 main(),操作系统会在程序启动时自动触发它。 |
| 执行顺序的起点 | 程序会从 main 函数的第一行代码开始逐行往下执行,直到遇到 return 语句或函数末尾。 |
| 程序的终点 | 当 main 函数执行完并返回时,整个程序也就随之运行结束并退出。 |
- 2️⃣ 标准的代码结构和拆解,如下所示:
// int(返回值类型):声明 main 函数执行完毕后会向操作系统返回一个整数(Integer)
// main(函数名):这是 C 语言规定的固定名称,不能拼错或改名,否则编译器会报错(提示找不到程序入口)。
// ()(参数列表): 括号内用来接收命令行传来的参数。如果不需要接收外部参数,可以留空或写 (void)。
int main() { // { ... }(函数体):大括号内部包含了该程序要执行的所有逻辑指令。
// 这里写业务逻辑代码
return 0; // return 0;(退出状态码)
// 告诉操作系统“程序已顺利执行完毕,正常退出”。
// 在约定俗成的规范中,返回 0 代表成功运行,返回非 0 的数字(如 1 或 -1)代表程序运行过程中遇到了错误。
}2
3
4
5
6
7
8
9
- 3️⃣ 常见的写法形式,如下所示:
| main 常见的写法形式 | 描述 | 推荐 |
|---|---|---|
| int main() | 无参数的标准写法,适合新手入门和绝大多数普通程序。 | 推荐 |
| int main(void) | 明确指定不接收任何命令行参数,语义最严谨。 | 推荐 |
| int main(int argc, char *argv[]) | 带命令行参数的写法,用于接收从终端/命令行输入的附加参数。 | 进阶推荐 |
| void main() | 无返回值的非标准写法,仅在少数老旧编译器或嵌入式环境中可用。 | 不推荐(不符合 ANSI C/C99 标准) |

第七章:CLion + Meson 实现多模块(🔥)
7.1 概述
- 在 C 语言开发中,并不像 Java 那样流行多模块,如下所示:

- 但是,通过构建工具(Meson、CMake 等),我们也能实现 Java 的那种多模块,如下所示:

7.2 单模块
7.2.1 概述
- 项目结构,如下所示:
c-demo1/---------------- # 项目根目录(项目名称:c-demo1)
│
├── meson.build--------- # Meson 构建系统的核心配置文件
│
├── include/------------ # 头文件目录(存放公共头文件、接口声明)
│ ├── user.h---------- # 用户模块头文件(声明用户相关的函数和结构体)
│ └── network.h------- # 网络模块头文件(声明网络通信相关的函数和结构体)
│
└── src/---------------- # 源文件目录(存放具体的业务逻辑和代码实现)
├── main.c---------- # 主程序入口文件(包含 main 函数,负责程序初始化)
├── user.c---------- # 用户模块实现文件(具体实现 user.h 中声明的函数逻辑)
└── network.c------- # 网络模块实现文件(具体实现 network.h 中声明的函数逻辑)2
3
4
5
6
7
8
9
10
11
12
提醒
- ① meson.build 是 Meson 构建系统的核心配置文件,类似于 Maven 项目中的 pom.xml 文件。
- ② src 是源文件目录,类似于 Maven 项目的 src/main/java 目录。
- ③ include 是头文件目录,其实相当于 Java 中的接口,类似于 Maven 项目的 src/main/java 目录。
- ④ C 语言项目单模块的 GitHub 地址。
7.2.2 创建步骤
- ① 新建项目,如下所示:

- ② 创建
src和include目录,并将main.c移动到src中,如下所示:

- ④ 将
src目录和include目录标记为项目源和头文件,如下所示:

- ⑤ 修改
meson.build配置文件,如下所示:
project('c-demo1', # 这是项目名(模块名)
'c',
version : '1.0.0',
default_options : ['warning_level=3', 'c_std=c2x'])
python = import('python').find_installation()
glob_result = run_command(
python,
'-c',
'''
import pathlib
import sys
root = pathlib.Path(sys.argv[1])
for path in sorted(root.rglob('*.c')):
print(path.as_posix())
''',
meson.project_source_root() / 'src',
check : true,
)
sources = glob_result.stdout().strip().split('\n')
c_demo1 = executable(
'c_demo1', # 这是项目名(模块名)
sources,
include_directories : include_directories('include'),
install : true,
)
test('test', c_demo1)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

- ⑥ 新增 mise.toml 配置文件,如下所示:
[tasks.setup]
description = "Initialize the Meson build directory"
run = "meson setup buildDir"
outputs = ["buildDir/build.ninja"]
[tasks.configure]
description = "Reconfigure Meson and rescan src/**/*.c"
depends = ["setup"]
run = "meson setup --reconfigure buildDir"
[tasks.build]
description = "Configure and build the project"
depends = ["configure"]
run = "meson compile -C buildDir"
[tasks.run]
description = "Build and run the program"
depends = ["build"]
# c_demo1 是项目(模块名)
run = "meson devenv -C buildDir c_demo1"
[tasks.test]
description = "Build and run all tests"
depends = ["build"]
run = "meson test -C buildDir --print-errorlogs"
[tasks.clean]
description = "Remove compiled outputs while keeping Meson configuration"
depends = ["setup"]
run = "meson compile -C buildDir --clean"
[tasks.install]
description = "Build and install the program"
depends = ["build"]
run = "meson install -C buildDir"2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

- ⑦ 在
include目录和src目录下新增模块,如下所示:
#ifndef C_DEMO1_ADD_H
#define C_DEMO1_ADD_H
int add(int a,int b);
#endif // C_DEMO1_ADD_H2
3
4
5
6
#include "add.h"
int add(int a, int b) {
return a + b;
}2
3
4
5

- ⑧ 在
main.c中使用该模块,如下所示:
#include "add.h"
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int c = add(a, b);
printf("a + b = %d\n", c);
printf("Hello, World!\n");
return 0;
}2
3
4
5
6
7
8
9
10
11
12
13

- ⑨ 目前,CLion 不支持自动加载,因此新增完代码文件之后,需要手动刷新项目,如下所示:

- ⑩ CLion 内部是调用 Meson 中的命令,我已经配置到了 mise.toml 的 task 中,如下所示:

- ⑪ 在项目中,增加
.clang-format文件和.clang-tidy文件,如下所示:
提醒
- ①
.clang-format(代码格式化配置文件):统一代码的 排版和视觉风格,不改变任何代码逻辑。 - ②
.clang-tidy(代码静态分析与 Lint 配置文件):检查代码的 潜在 Bug、性能缺陷、编码规范与现代 C++ 最佳实践。
BasedOnStyle: LLVM
# ============================================================
# Java 风格基础
# ============================================================
# 4 空格缩进
IndentWidth: 4
ContinuationIndentWidth: 4
TabWidth: 4
UseTab: Never
# 不因为长度强制折行
ColumnLimit: 0
# ============================================================
# 大括号:Java 风格
# ============================================================
# int main() {
# if (...) {
# } else {
BreakBeforeBraces: Attach
# ============================================================
# 短语句
# ============================================================
# 允许空函数:
#
# void foo() {}
AllowShortFunctionsOnASingleLine: Empty
# 不允许:
#
# if (a) foo();
AllowShortIfStatementsOnASingleLine: Never
# 不允许:
#
# while (...) foo();
AllowShortLoopsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
# ============================================================
# 空行
# ============================================================
MaxEmptyLinesToKeep: 1
KeepEmptyLines:
AtStartOfBlock: false
AtStartOfFile: false
AtEndOfFile: false
# ============================================================
# 空格:Java 风格
# ============================================================
# if (...) / for (...) / while (...)
# 但是 printf(...)
SpaceBeforeParens: ControlStatements
SpacesInParens: Never
SpacesInAngles: Never
SpacesInContainerLiterals: false
# ============================================================
# 指针:保持 C 的惯用写法
# ============================================================
# char *name
# char **argv
DerivePointerAlignment: false
PointerAlignment: Right
# ============================================================
# switch:Java 风格
# ============================================================
IndentCaseLabels: true
# ============================================================
# 对齐
# ============================================================
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
# 对齐连续代码行末尾的注释;空行会分隔不同的对齐组
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
# ============================================================
# include
# ============================================================
IncludeBlocks: Regroup
SortIncludes:
Enabled: true
IgnoreCase: true
# 标准库在上,自定义头文件在下;不同类别之间保留空行
IncludeCategories:
- Regex: '^<.*>'
Priority: 1
- Regex: '^".*"'
Priority: 2
# ============================================================
# 注释
# ============================================================
ReflowComments: Always2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
---
Checks: >-
-*,
clang-analyzer-*,
bugprone-*,
cert-*,
portability-*
WarningsAsErrors: '*'
HeaderFilterRegex: '^(include|modules|tools)[\\/]'
FormatStyle: none
...2
3
4
5
6
7
8
9
10
11

7.3 多模块
7.3.1 概述
- 项目结构,如下所示:
c-demo2/
├── meson.build # 加载 common 和生成的模块清单
├── common/
│ ├── meson.build # 可选的公共静态库
│ ├── include/common.h
│ └── src/common.c
├── 00.intro/
│ └── 01.hello-world/
│ ├── meson.build # 独立目标
│ ├── include/hello.h
│ └── src/
│ ├── hello.c
│ └── main.c # 独立可执行程序
├── 02.common-demo/
│ ├── meson.build # 独立目标
│ ├── include/demo.h
│ └── src/
│ ├── demo.c
│ └── main.c # 独立程序,并显式依赖 common
└── mise.toml2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
提醒
- ① meson.build 是 Meson 构建系统的核心配置文件,类似于 Maven 项目中的 pom.xml 文件。
- ② src 是源文件目录,类似于 Maven 项目的 src/main/java 目录。
- ③ include 是头文件目录,其实相当于 Java 中的接口,类似于 Maven 项目的 src/main/java 目录。
- ④ 约定含有 meson.build 配置文件的就是子模块。
- ⑤ C 语言项目多模块的 GitHub 地址
7.3.2 创建步骤
- ① 新建项目,如下所示:

- ② 创建 common 模块,如下所示:
提醒
约定每个模块必须含有 src 目录和 include 目录!!!
#ifndef COMMON_H
#define COMMON_H
#include <locale.h>
#include <stdio.h>
// 立即显示教学示例的输出,并采用当前平台的 UTF-8 locale。
void init_runtime(void);
#ifdef COMMON_IMPLEMENTATION
#if defined(__GNUC__) || defined(__clang__)
__attribute__((constructor))
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU", read)
#endif
void init_runtime(void) {
if (setvbuf(stdout, NULL, _IONBF, 0) != 0) {
(void)fputs("warning: failed to disable stdout buffering\n", stderr);
}
#ifdef _WIN32
const char *locale_name = ".UTF-8";
#else
const char *locale_name = "";
#endif
if (setlocale(LC_ALL, locale_name) == NULL) {
(void)fputs("warning: failed to configure the user locale\n", stderr);
}
}
#if defined(_MSC_VER) && !defined(__clang__)
__declspec(allocate(".CRT$XCU"))
void (__cdecl * const init_runtime_initializer)(void) = init_runtime;
#endif
#endif
// 下面的代码可以删除
int add(int a, int b);
int sub(int a, int b);
#endif // COMMON_H2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#define COMMON_IMPLEMENTATION
#include "common.h"
// 下面的代码可以删除
int add(int a, int b) {
return a + b;
}
int sub(int a, int b) {
return a - b;
}2
3
4
5
6
7
8
9
10
11
common_scan = run_command(
python,
'-c',
'''
from pathlib import Path
import sys
root = Path(sys.argv[1]).resolve()
for path in sorted((*root.rglob('*.c'), *root.rglob('*.h'))):
print(path.relative_to(root).as_posix())
''',
meson.current_source_dir(),
check : true,
).stdout().strip()
common_files = common_scan.split('\n')
common_inc = include_directories('include')
common_lib = static_library(
'common',
common_files,
include_directories : common_inc,
)
# 练习模块通过 dependencies : common_dep 使用公共代码。
common_dep = declare_dependency(
# 整体链接以保证无须显式调用的运行时初始化入口不会被静态链接器丢弃。
link_whole : common_lib,
include_directories : common_inc,
)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

- ③ 修改项目根目录的
meson.build文件,如下所示:
project(
'c-demo1',
'c',
version : '1.0.0',
default_options : ['warning_level=3', 'c_std=c2x'],
)
# 自动发现根目录以下的 meson.build;公共库必须先于所有练习模块加载。
python = import('python').find_installation()
submodule_result = run_command(
python,
'-c',
'''
from pathlib import Path
import sys
root = Path(sys.argv[1]).resolve()
build_files = sorted(
root.rglob('meson.build'),
key=lambda path: (path.parent != root / 'common', path.as_posix()),
)
for build_file in build_files:
if build_file.parent != root:
print(build_file.parent.relative_to(root).as_posix())
''',
meson.project_source_root(),
check : true,
).stdout().strip()
if submodule_result != ''
foreach submodule_dir : submodule_result.split('\n')
subdir(submodule_dir.strip())
endforeach
endif2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

- ④ 新增
mise.toml、.clang-tidy以及.clang-format文件,如下所示:
[tasks.setup]
description = "Initialize the Meson build directory"
run = "meson setup buildDir"
outputs = ["buildDir/build.ninja"]
[tasks.configure]
description = "Reconfigure Meson and rescan src/**/*.c"
depends = ["setup"]
run = "meson setup --reconfigure buildDir"
[tasks.build]
description = "Configure and build the project"
depends = ["configure"]
run = "meson compile -C buildDir"
[tasks.run]
description = "Build and run a module: mise run run <module-name>"
depends = ["build"]
run = "meson test -C buildDir --verbose"
[tasks.clean]
description = "Remove compiled outputs while keeping Meson configuration"
depends = ["setup"]
run = "meson compile -C buildDir --clean"
[tasks.install]
description = "Build and install the program"
depends = ["build"]
run = "meson install -C buildDir"2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
---
Checks: >-
-*,
clang-analyzer-*,
bugprone-*,
cert-*,
portability-*
WarningsAsErrors: '*'
HeaderFilterRegex: '^(include|modules|tools)[\\/]'
FormatStyle: none
...2
3
4
5
6
7
8
9
10
11
BasedOnStyle: LLVM
# ============================================================
# Java 风格基础
# ============================================================
# 4 空格缩进
IndentWidth: 4
ContinuationIndentWidth: 4
TabWidth: 4
UseTab: Never
# 不因为长度强制折行
ColumnLimit: 0
# ============================================================
# 大括号:Java 风格
# ============================================================
# int main() {
# if (...) {
# } else {
BreakBeforeBraces: Attach
# ============================================================
# 短语句
# ============================================================
# 允许空函数:
#
# void foo() {}
AllowShortFunctionsOnASingleLine: Empty
# 不允许:
#
# if (a) foo();
AllowShortIfStatementsOnASingleLine: Never
# 不允许:
#
# while (...) foo();
AllowShortLoopsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
# ============================================================
# 空行
# ============================================================
MaxEmptyLinesToKeep: 1
KeepEmptyLines:
AtStartOfBlock: false
AtStartOfFile: false
AtEndOfFile: false
# ============================================================
# 空格:Java 风格
# ============================================================
# if (...) / for (...) / while (...)
# 但是 printf(...)
SpaceBeforeParens: ControlStatements
SpacesInParens: Never
SpacesInAngles: Never
SpacesInContainerLiterals: false
# ============================================================
# 指针:保持 C 的惯用写法
# ============================================================
# char *name
# char **argv
DerivePointerAlignment: false
PointerAlignment: Right
# ============================================================
# switch:Java 风格
# ============================================================
IndentCaseLabels: true
# ============================================================
# 对齐
# ============================================================
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
# 对齐连续代码行末尾的注释;空行会分隔不同的对齐组
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
# ============================================================
# include
# ============================================================
IncludeBlocks: Regroup
SortIncludes:
Enabled: true
IgnoreCase: true
# 标准库在上,自定义头文件在下;不同类别之间保留空行
IncludeCategories:
- Regex: '^<.*>'
Priority: 1
- Regex: '^".*"'
Priority: 2
# ============================================================
# 注释
# ============================================================
ReflowComments: Always2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

- ⑤ 新增子模块,如下所示:
提醒
约定只要包含有 meson.build 的目录就是子模块,并且子模块的 src 是源文件目录,而 include 是头文件目录。
#ifndef C_DEMO2_HELLO_H
#define C_DEMO2_HELLO_H
void print_hello(void);
#endif // C_DEMO2_HELLO_H2
3
4
5
6
#include <stdio.h>
#include "hello.h"
void print_hello(void) {
puts("Hello from an independent module!");
}2
3
4
5
6
7
#include "common.h"
#include "hello.h"
int main(void) {
printf("你好,世界\n");
print_hello();
return 0;
}2
3
4
5
6
7
8
9
# 当前目录是一个独立模块,只收集该模块边界内的 C 源文件和头文件。
scan_result = run_command(
python,
'-c',
'''
from pathlib import Path
import re
import sys
root = Path(sys.argv[1]).resolve()
project_root = Path(sys.argv[2]).resolve()
files = sorted((*root.rglob('*.c'), *root.rglob('*.h')))
main_files = [
path for path in files
if path.name == 'main.c' and re.search(r'\bmain\s*\(', path.read_text(encoding='utf-8'))
]
if len(main_files) != 1:
raise SystemExit(f'{root}: expected exactly one main.c defining main(), found {len(main_files)}')
# 使用从项目根目录到当前模块的完整目录路径,避免不同上级目录中的
# 同名模块生成相同的 Meson/CLion 目标名。
relative_module = root.relative_to(project_root)
print(re.sub(r'[^A-Za-z0-9_]', '_', relative_module.as_posix()))
for path in files:
print(path.relative_to(root).as_posix())
''',
meson.current_source_dir(),
meson.project_source_root(),
check : true,
).stdout().strip()
scan_records = scan_result.split('\n')
module_target = scan_records[0]
module_files = []
foreach index : range(scan_records.length())
if index > 0
module_files += scan_records[index]
endif
endforeach
module = executable(
module_target,
module_files,
include_directories : include_directories('include'),
dependencies : common_dep,
)
test(module_target, module)2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

- ⑥ 目前,CLion 不支持自动加载,因此新增完代码文件之后,需要手动刷新项目,如下所示:

- ⑦ CLion 内部是调用 Meson 中的命令,我已经配置到了 mise.toml 的 task 中,如下所示:
