C 语言主题:性能剖析的母语
更新时间:2026-08-25。本文是
languages/域落地主题 C 语言 的总纲。本站的性能剖析主线(perf、/proc、缓存一致性、内存屏障)几乎全部建立在 C 语言之上——看懂 C,是看懂一切底层性能数据的前提。
为什么本站要讲 C
本站的核心演示程序 demos/cpu-demo 就是 C++ 写的,而 perf、top、strace 这类观测工具的内部实现、Linux 内核、以及你剖析的绝大多数性能热点程序,全是 C/C++。C 语言离硬件最近,是理解"程序为什么慢"的最佳入口:
| C 特性 | 对应的本站主线知识 | 为什么重要 |
|---|---|---|
| 指针与地址 | L5 ELF / 内存布局 | 指针就是地址,perf 火焰图里的每个帧都是符号+偏移 |
| 手动内存管理 | L3 内存子系统 | malloc/free 决定堆分配路径,影响缓存与 TLB |
| 编译器优化 | L4 编译器选项 | -O0/-O2/-O3 直接改变生成代码,cpu-demo 的教学点 |
| volatile / restrict | L4 内存重排 | 告诉编译器"别乱动我的内存",与屏障语义同源 |
| 类型与内存布局 | L3 对齐与 TLB | struct 的字段顺序决定内存对齐,影响缓存命中 |
一句话定位:languages/c/ 把"性能剖析看到的底层现象"翻译成"C 语言怎么写、内存怎么管、程序怎么编译运行"——语言与底层原理在这里合流。
学习路径:入门 → 高手 → 专家(三层递进)
C 语言主题按「入门 / 高手 / 专家」三层组织,层层递进、覆盖 C 的大部分知识点:

| 层 | 目录 | 文档 | 产出 |
|---|---|---|---|
| 入门 | beginner/ | 数据类型与内存表示、控制流与函数、数组、字符串与结构体 | 能写正确的 C 小程序 |
| 高手 | intermediate/ | 指针深入、动态内存管理、文件 IO 与模块化、预处理、宏与调试 | 能写工程、能排查内存 bug |
| 专家 | expert/ | 编译、链接与 ELF、内存布局与 ABI、与汇编、性能剖析衔接 | 理解底层、看懂 perf 数据 |
一、语法速览(10 分钟扫盲)
1.1 最小程序:main 是入口
#include <stdio.h>
int main(void) {
printf("Hello, 极客教程\n");
return 0;
}- 编译运行:
gcc -O0 -g -o hello hello.c && ./hello——本站所有 demo 都沿用-O0 -g约定(保留符号便于perf定位)。 main返回int,0表示成功,非 0 表示出错。
1.2 基本类型与格式化
int i = 42; // 有符号整型
char c = 'A'; // 字符,本质是 1 字节整型
float f = 3.14f; // 单精度
double d = 3.14159; // 双精度
size_t n = 10; // 无符号长度类型,sizeof 的返回类型用 printf 格式化输出:%d(整型)、%c(字符)、%f(浮点)、%zu(size_t)、%p(指针)。
1.3 指针:C 语言的核心
int x = 10;
int *p = &x; // p 保存 x 的地址
*p = 20; // 通过 p 修改 x
printf("x=%d *p=%d\n", x, *p); // x=20 *p=20&取地址,*解引用——指针就是内存地址,这是它与汇编lea/mov指令一一对应的原因。NULL表示空指针;解引用空指针会段错误(SIGSEGV),这是 crash 排查线 最常见的一类。
1.4 数组与字符串
int a[3] = {1, 2, 3};
printf("%d\n", a[1]); // 2,a[1] 等价于 *(a + 1)
char s[] = "hello"; // 字符数组,末尾自动补 '\0'
printf("%zu\n", sizeof(s)); // 6(含结束符)数组名在大多数表达式中退化为首元素地址——这是 C 新手最容易混淆的点,详见指针与内存管理。
1.5 结构体与 typedef
typedef struct {
const char *name;
int cores;
} CpuInfo;
CpuInfo cpu = {"EPYC 7K62", 64};
printf("%s %d\n", cpu.name, cpu.cores);struct 的内存布局由字段顺序和对齐规则决定,直接影响缓存命中——这是 L3 内存子系统 反复强调的点。
1.6 控制流:与主流语言一致
for (int i = 0; i < 10; i++) { /* ... */ }
while (n-- > 0) { /* ... */ }
if (x > 0) { /* ... */ } else { /* ... */ }
switch (c) { case 'A': break; default: break; }注意 for 里的 int i 是 C99 才允许的声明,老代码可能写作 int i; for (i = 0; ...)。
二、C 与汇编的距离
C 被称为"可移植汇编"——它的核心特性几乎都能映射到指令级:
| C 代码 | 典型汇编(x86-64) | 说明 |
|---|---|---|
int x = 10; | movl $10, -4(%rbp) | 常量写栈 |
int *p = &x; | leaq -4(%rbp), %rax | 取地址 = 计算地址 |
*p = 20; | movl $20, (%rax) | 解引用 = 访存 |
a[1] | movl 4(%rdx), %eax | 数组下标 = 基址+偏移 |
x > 0 | cmpl $0, %eax / jle | 比较+条件跳转 |
sum += i; | addl %esi, %eax | 算术指令 |
用 objdump -d 或 gcc -S 可以把任何 C 函数变成汇编查看——这也是 perf 反汇编热点 时看到的视图。
为什么本站强调 -O0 -g:-O0 保留最直白的指令序列(每行 C 对应多行汇编),-g 保留符号与行号,perf 才能把热点定位到具体行——这正是 demos/cpu-demo 的默认构建约定。
三、C 语言性能剖析主线衔接
C 程序变慢了,与 Go/Java 完全不同的地方在于:你直接观察的就是机器本身。

衔接文档:
- 编译优化:本站 demos/cpu-demo 演示
-O2如何消除sum += i循环(教学点)。 - 内存布局:struct 对齐、malloc 分配路径,见 L3 内存子系统。
- ELF 与装载:链接后生成的可执行文件格式,见 编译、链接与 ELF。
- 崩溃排查:段错误/越界/泄漏,见 crash 排查线。
四、C vs 其他语言
| 对比项 | C | C++ | Go | Python |
|---|---|---|---|---|
| 抽象层级 | 最接近硬件 | 零成本抽象 | 中等 | 最高 |
| 内存管理 | 手动 malloc/free | RAII/智能指针 | GC | GC |
| 指针 | 原生指针 | 指针+引用 | 指针(受限) | 无 |
| 性能 | 极高 | 极高 | 高 | 低 |
| 本站定位 | 性能剖析母语 | 底层实验主力 | 业务并发 | 辅助脚本 |
本站建议:性能剖析主线以 C 打底(perf//proc 的语义全是 C 的),C++ 承接底层实验(RAII 更安全),Go 做业务并发。
一句话总结
C 语言主题 = 入门(语法上手)→ 高手(工程实践)→ 专家(底层机制)三层递进,把"性能剖析的底层现象"翻译成语言直觉;看懂 C,你就看懂了 perf 火焰图、/proc 数据和可执行文件本身。
深入:入门从 数据类型与内存表示 开始 → 高手读 指针深入 → 专家读 内存布局与 ABI。相邻主题:C++ 现代特性。