去年两次参加软考高级架构师考试,都是在某个老牌顶级名校,在他们的书店里发现很多教材用的还是VC98之类的古董。这玩意儿在我们当年学的时候就已经显得陈旧了。
前些年就开始教授基础的编程入门课程,既教Python,也教C语言基础知识。我教学时一般使用苏小红老师的教材,其中有一些章节是孙志岗老师编写的,他们采用的是Code Blocks,这个工具也还不错,可以安装集成GCC的版本,网上资料也很丰富。
但从今年开始,我考虑换一个思路。今年准备采用Clang,Clang是LLVM项目提供的现代化C/C++/Objective-C编译器,以编译快、内存省、报错清晰著称。Clang可以搭配Void/Trae/Qoder之类的现代编辑器,以及之前我们介绍过的OpenCode和Ollama,让同学们能够直接使用当前最前沿的工具链。
下面就简单介绍一下如何安装Clang以及配置环境变量。
Windows 系统下使用 Winget 安装
如果你使用的是Windows系统,建议尽量多用Winget,而不要去网站下载安装包,这样既能提高安全性,也能省去很多麻烦。
如何使用Winget呢?很简单,按下快捷键Win+X,然后点击"终端(管理员)",如下图所示:

这样就能进入PowerShell,注意一定要是PowerShell,不能是cmd,因为命令不一样。
winget install LLVM.LLVM
然后默认安装位置在
C:\Program Files\LLVM\bin
Windows 系统下环境变量设置
刚安装完成时,你直接运行clang肯定会出错,会提示类似下面的错误信息:
clang
clang : The term 'clang' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is
correct and try again.
At line:1 char:1
+ clang
+ ~~~~~
+ CategoryInfo : ObjectNotFound: (clang:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
这是因为刚刚安装好的clang目录没有被添加到系统的环境变量里,所以系统找不到它,这时候就需要手动将上述目录添加到环境变量中。
这也很简单,还是按Win+X,选择"终端(管理员)",进入PowerShell,注意一定要是PowerShell,不能是cmd,因为命令不一样。 然后运行下面这段命令,注意仔细复制粘贴,不要遗漏任何字符:
[Environment]::SetEnvironmentVariable("Path", $([Environment]::GetEnvironmentVariable("Path","Machine")) + ";C:\Program Files\LLVM\bin", "Machine")
上面的命令执行成功后,需要新建一个终端窗口(注意,一定要是新建的),才能加载新设置的环境变量,然后再运行验证命令。
clang --version
会得到
clang version 21.1.8
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\LLVM\bin
Ubuntu 系统下的安装和使用
如果使用的是Ubuntu系统,那就更方便了,直接使用apt安装即可:
# 首先更新软件包列表
sudo apt update
# 然后安装Clang本体
sudo apt install clang
# 接着安装一些依赖库
sudo apt install libc++-dev libc++abi-dev
# 然后就可以直接使用了
clang --version
就会得到下面的输出:
Ubuntu clang version 18.1.3 (1ubuntu1)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Clang 的最基础用法
假设当前目录下有一份名为hello.c的C语言代码文件,内容如下:
#include <stdio.h> // 标准输入输出(printf, scanf)
#include <stdlib.h> // 标准库(malloc, free, EXIT_SUCCESS)
#include <string.h> // 字符串操作(strcpy, strlen)
#include <math.h> // 数学函数(sqrt, pow)
#include <stdbool.h> // 布尔类型(bool, true, false)
// 函数声明(可选,因定义在 main 之后)
double compute_hypotenuse(double a, double b);
int main(void) {
// === 基本数据类型 ===
int age = 25; // 整型
short count = 100; // 短整型
long big_num = 123456789L; // 长整型
long long huge_num = 9876543210LL; // 更长整型
float price = 19.99f; // 单精度浮点
double pi = 3.1415926535; // 双精度浮点
char grade = 'A'; // 字符(ASCII)
unsigned char byte_val = 255; // 无符号字符
bool is_valid = true; // 布尔值(C99起)
// === 构造类型:数组、结构体、枚举 ===
int scores[3] = {90, 85, 95}; // 数组
struct Student { // 结构体
char name[20];
int age;
double gpa;
} stu = {"Alice", 20, 3.8};
enum Color { RED, GREEN, BLUE }; // 枚举
enum Color bg = GREEN;
// === 指针与动态内存 ===
int *p = &age; // 指针(指向 age)
int *arr = malloc(5 * sizeof(int)); // 动态分配数组
if (arr == NULL) return EXIT_FAILURE;
for (int i = 0; i < 5; i++) arr[i] = i * 2;
// === 使用标准库函数 ===
printf("Hello, %s! Age: %d\n", stu.name, stu.age);
printf("Pi is about %.6f, sqrt(2) is about %.4f\n", pi, sqrt(2.0));
printf("Hypotenuse of (3,4): %.2f\n", compute_hypotenuse(3.0, 4.0));
// === 控制结构 ===
if (is_valid) {
printf("Status: Valid\n");
}
for (int i = 0; i < 3; i++) {
printf("Score[%d] = %d\n", i, scores[i]);
}
// === 释放动态内存 ===
free(arr);
return EXIT_SUCCESS; // 程序正常退出
}
// === 自定义函数 ===
double compute_hypotenuse(double a, double b) {
return sqrt(a * a + b * b); // 调用 math.h 中的 sqrt
}
上面的代码内容可能比较多,其实涵盖了C语言的基础知识点,大家现在不用太在意细节。
# 编译 C 程序
clang hello.c -o hello.exe
./hello.exe
然后就会得到类似下面的输出:
Hello, Alice! Age: 20
Pi is about 3.141593, sqrt(2) is about 1.4142
Hypotenuse of (3,4): 5.00
Status: Valid
Score[0] = 90
Score[1] = 85
Score[2] = 95
上面使用了.exe扩展名,这是针对Windows用户的。
在Unix-like系统(如Linux或macOS)中,可执行文件通常不带.exe后缀;.exe是Windows的惯用命名方式。因此在这些系统中建议输出为hello而非hello.exe,如下所示:
# 编译 C 程序
clang hello.c -o hello
./hello
Clang 的进阶使用
其实前面的编译过程还可以添加很多选项。另外,严格来说这里实际上完成了编译、链接等多个步骤,只是在此处简称为编译。
| 选项 | 作用 |
|---|---|
-std=c11 |
指定使用C11标准(推荐,因代码使用了bool等C99+特性) |
-O2 |
启用推荐的优化等级,适用于发布版本 |
-g |
生成调试信息,便于使用GDB或LLDB调试 |
-Wall |
开启常见警告,帮助发现潜在问题 |
-Wextra |
启用更多额外警告(可选但推荐) |
-lm |
在Linux或macOS下链接数学库(因代码调用了sqrt和pow) |
重要:在Linux或macOS系统下,链接数学库时,-lm选项必须放在源文件之后,否则可能导致链接失败:
clang -std=c11 -O2 -Wall -g hello.c -o hello.exe # ✅ Windows
clang -std=c11 -O2 -Wall -g hello.c -lm -o hello # ✅ Linux或macOS
clang -lm hello.c -o hello # ❌ 可能报错
完整推荐命令:
clang -std=c11 -O2 -Wall -Wextra -g hello.c -o hello.exe # ✅ Windows
clang -std=c11 -O2 -Wall -Wextra -g hello.c -lm -o hello # ✅ Linux或macOS
Clang 的简单静态分析
Clang内置静态分析器,可以在不运行程序的情况下发现空指针解引用、未初始化变量等问题:
clang --analyze hello.c
就会提示
hello.c:38:10: warning: Value stored to 'p' during its initialization is never read
[deadcode.DeadStores]
38 | int *p = &age; // 指针(指向 age)
| ^ ~~~~
1 warning generated.
若代码中存在如malloc失败未处理等风险,分析器会给出相应提示。
如果你想要了解编译器如何理解你的代码:
clang -S -emit-llvm hello.c -o hello.ll
生成的hello.ll是人类可读的LLVM IR,可用于学习编译原理或进行手动优化。
CycleUser