1) 编译/链接与构建
预处理/编译/汇编/链接四阶段分别做什么
头文件与多重包含:include guard vs
#pragma once声明 vs 定义:
extern的真实含义翻译单元、符号可见性、重复定义与 ODR-like 问题(C 里表现为链接冲突)
静态库
.a/ 动态库.so:链接顺序、依赖、导出符号常见编译器选项:
-Wall -Wextra -Werror -O2 -g -fsanitize=address,undefined调试信息、优化对调试的影响(变量“消失”、栈回溯变化)
2) 内存模型与对象生命周期
栈/堆/静态存储区/只读区(字符串常量)差异
对象生命周期:自动存储期 / 静态存储期 / 动态存储期
malloc/calloc/realloc/free语义与陷阱:realloc 失败、对齐、0 字节内存泄漏、悬垂指针、重复释放、越界读写的典型模式
对齐与
sizeof/alignof(C11)/ paddingrestrict的语义(优化相关)
3) 指针与数组高阶用法
数组退化、
sizeof(a)vssizeof(p)(函数参数退化)指针算术:元素大小、越界即 UB(即使不解引用也可能 UB,取决于标准语境)
二维数组传参:
int (*p)[N]、VLA 形参函数指针:回调、表驱动、比较函数(qsort)
void*与类型擦除:正确转换、别名问题常见易错:
char*指向字符串常量的写入、int*强转对齐问题
4) 结构体/联合体/位域
结构体内存布局、padding、
#pragma pack风险指定初始化(C99)与复合字面量
union的使用场景与风险(类型双关/别名 UB)位域:实现相关、跨平台不可移植点(顺序、对齐、符号扩展)
5) 类型系统与整数/浮点细节
整数提升(integer promotions)、通常算术转换(usual arithmetic conversions)
有符号/无符号混算坑:比较、溢出
溢出规则:有符号溢出 UB;无符号按模运算
浮点精度、比较、NaN、舍入模式
uintptr_t、size_t、ptrdiff_t的正确使用
6) 未定义行为/实现定义/未指定行为(C 进阶核心)
常见 UB:越界、使用未初始化值、空指针解引用、严格别名违规、移位越界、释放后使用
序列点/求值顺序(C11 起更清晰但仍有坑)
volatile不是线程同步工具;它解决的是“可见性/副作用”而不是“原子性”
7) 宏与预处理器高级技巧
宏函数的副作用与括号规则
do { ... } while (0)模式#字符串化、##连接X-Macro:表驱动生成枚举/字符串映射
条件编译与平台适配:
#if defined(...)
8) const / 指针 const 组合
const int *pvsint * const pvsconst int * const pconst与 API 设计:输入只读、返回指针的生命周期契约const不能保证对象真的不可变(可能被别名修改)
9) 标准库与常用坑
字符串:
strncpy的坑、snprintf的安全用法memcpyvsmemmoveI/O:
fgets、缓冲、二进制/文本模式差异errno的使用规范时间/随机:
rand()质量问题、种子管理
10) 线程与并发(C11)
_Atomic、原子操作、内存序(relaxed/acquire/release/seq_cst)数据竞争、可见性、重排序
线程库(若用 pthread):mutex/cond、死锁模式、伪共享
11) 代码组织与工程实践
模块化:
.h暴露最小接口、.c隐藏实现错误处理风格:返回码 vs
errnovs out-parameter资源管理:手动 RAII 风格(goto cleanup)
日志、断言(
assert)、契约式编程可移植性:不同编译器/字节序/对齐/大小端
12) 调试与工具链(强烈建议掌握)
gdb/lldb:断点、watchpoint、栈回溯、core dump
sanitizers:ASan/UBSan/TSan
valgrind(内存泄漏/越界)
静态分析:clang-tidy、cppcheck
。
评论