C 语言未定义行为与优化
更新时间:2026-08-26。本文是
languages/c/主题专家层的骨架文档(占位),完整展开将在后续批次补齐。
本文要回答的问题
- 什么是"未定义行为"?它和"实现定义"有什么区别?
- 为什么写了 UB 的代码,
-O0能跑、-O2就崩? - 怎么用工具把 UB 找出来?
一、UB 是什么
C 标准把程序行为分四档:定义良好(按标准执行)、实现定义(各编译器自定,但必须文档化)、未指定(编译器选一个合理行为即可)、未定义行为 UB(标准完全不管,编译器做什么都"合法")。
| 常见 UB | 例子 |
|---|---|
| 越界访问 | 数组下标越界、野指针解引用 |
| 有符号溢出 | INT_MAX + 1 |
| 除零 | 整数除以 0 |
| 空指针解引用 | *NULL |
| 未初始化读取 | 读未赋值的局部变量 |
| 重复定义 | 同名强符号多个定义 |
二、优化器如何利用 UB
编译器看到"这条路径是 UB"时,会假设它不会发生,从而自由优化:
c
int f(int x) { return x + 1 > x; } // 有符号溢出是 UB
// -O2 下编译器可能直接返回 1,因为"合理"假设 x+1 不会溢出所以同一段 UB 代码,-O0 碰巧按直觉跑、-O2 按优化假设跑——行为分叉,这是"优化后出诡异 bug"的根源。
三、检测与防御
-fsanitize=undefined(UBSan):运行时捕获溢出、越界、除零等,见 ASan/UBSan 检测。-Wall -Wextra -Werror:把常见 UB 隐患挡在编译期。- 规范写法:有符号运算前先判断范围;数组访问先查边界。
四、与入门层的衔接
一句话总结
UB 是 C 给优化器的"自由通行证":代码一进 UB 领域,-O0 和 -O2 就可能各说各话,用 UBSan + 严格警告把 UB 挡在门外。
本文为骨架文档:核心结构已就位,更多示例与实验将在后续批次补齐。