1
为什么学 C,以及把环境搭起来
Why C · Setup · Hello World · Build Pipeline
很多人问:"现在都 Python、Go 了,学 C 还有啥用?"答案很现实:你想进操作系统、编译器、数据库、嵌入式、游戏引擎这几个行当,绕不开 C;就算不去,学一遍 C 也能让你看懂"为什么 Python 的列表 append 要收费"这种底层账。它是理解计算机的一把解剖刀。
论C 的脾气:它把责任全甩给你
是什么:C 是一门"贴着硬件"的语言。你要自己管内存、自己数字节、自己保证数组别越界——它不帮你兜底。
代价:这意味着写错了不会像 Python 那样温柔报错,而是直接段错误(segmentation fault),程序当场猝死,一脸懵。
回报:正因为它不管你,所以它极快、极小、几乎能在任何有 CPU 的地方跑。快和小,是拿"你得多操点心"换来的。
装编译器:GCC / Clang / MinGW
C 不是解释执行的,它得先"编译"成机器码才能跑。所以你需要一个编译器。三个主流选择:
| 平台 | 怎么装 | 装完验证 |
|---|---|---|
| macOS | 打开终端,敲 xcode-select --install,装的就是 Clang。 | 终端输入 clang --version,看到版本号即成功。 |
| Linux (Ubuntu/Debian) | sudo apt install build-essential,装的是 GCC。 | gcc --version。 |
| Windows | 推荐装 MinGW-w64(或装 MSYS2),拿到 gcc.exe;也可直接用 Visual Studio 的 MSVC。 | 在命令行敲 gcc --version 能出版本即可。 |
第一个程序:Hello World
新建一个文件叫 hello.c(注意后缀必须是 .c),写下下面这几行。别着急,每一行都有讲究。
hello.c —— 程序员世界的"你好,世界"
// 告诉编译器:我要用标准输入输出这一套工具
#include <stdio.h>
// main 是程序的入口,操作系统从这里开始执行
int main() {
printf("Hello, %s! 你好,世界\n", "C"); // 打印一句话,\n 是换行
return 0; // 返回 0 告诉操作系统:一切正常,没出乱子
}
编译并运行(macOS/Linux 终端)
$ gcc hello.c -o hello # 把源码编译成可执行文件 hello
$ ./hello # 运行它
Hello, C! 你好,世界
新手第一坑
忘记分号 ;、漏写 #include <stdio.h>、把 main 拼成 mian,是新手三大死因。编译器报错时别害怕,它骂的那行通常就是你手滑的地方。报错信息最后一行最值钱,前面的可以忽略。
编译过程:你的 .c 文件经历了什么
你敲一下 gcc hello.c,背后其实跑了四道工序。看懂这个,以后排查"链接错误""宏没生效"就知道去哪查。
| 阶段 | 干了什么 | 典型错误在哪冒出来 |
|---|---|---|
| 预处理 preprocess | 把 #include 展开、#define 替换、删注释。产出 .i 文件。 | 头文件找不到、宏不生效。 |
| 编译 compile | 把预处理后的代码翻译成汇编语言 .s。 | 语法错误、类型不匹配——最常报红字的阶段。 |
| 汇编 assemble | 把汇编翻译成机器码(二进制指令),产出 .o 目标文件。 | 一般不出错。 |
| 链接 link | 把你的 .o 和库函数(比如 printf 的实现)拼一起,凑成可执行文件。 | undefined reference to ...——函数写了没定义、库没链上。 |
gcc 常用参数:记住这五个就够
| 参数 | 作用 |
|---|---|
-o 文件名 | 指定输出的可执行文件名,不写就默认 a.out。 |
-Wall | 打开所有常用警告。必加——很多 bug 警告阶段就能拦下来。 |
-g | 生成调试信息,配合 gdb 单步调试时用。 |
-O2 | 开启二级优化。写正式程序时加,跑题更快。 |
-std=c11 | 指定用 C11 标准编译。想尝鲜 C23 就写 -std=c23。 |
一条推荐的日常编译命令
gcc -Wall -g -std=c11 hello.c -o hello
# │ │ │ │ └─ 输出叫 hello
# │ │ │ └─ 用 C11 标准
# │ │ └─ 留调试信息
# │ └─ 打开所有警告
# └─ 编译器