5.5 未定义行为

本篇学习 C 中未定义行为的含义、常见来源和规避思路,并能识别高风险写法。

未定义行为

概念说明

未定义行为表示 C 标准没有规定某段代码必须产生什么结果。 一旦程序进入这种状态,可能“看起来能跑”、可能输出随机结果,也可能在不同编译器或优化级别下表现完全不同。

很多初学者会把未定义行为理解成“只是不太稳定”。 实际上更准确的理解是:你已经离开了语言保证的范围,后续任何现象都不值得依赖。

这也是为什么 C 程序的调试不能只看一次运行结果。 某段代码今天在你的电脑上“似乎没问题”,并不代表它就是合法写法。

语法/规则

  1. 使用未初始化局部变量、数组越界、空指针解引用,都可能触发未定义行为。
  2. 有符号整数溢出、释放后继续访问内存,也是常见未定义行为来源。
  3. 某段代码在你电脑上“每次都一样”,不代表它就是合法行为。
  4. 预防未定义行为的关键是初始化、边界检查、资源管理和减少危险写法。
  5. 编译优化会放大未定义行为带来的不可预测后果,因此 Debug 和 Release 结果可能差异很大。
  6. 警告、静态分析和运行时检测工具能帮助你更早发现这类问题,但前提仍是代码本身要尊重边界。

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <stdio.h>

int main(void) {
    int nums[3] = {1, 2, 3};
    int index = 2;

    if (index >= 0 && index < 3) {
        printf("value = %d\n", nums[index]);
    }

    return 0;
}

输出结果:

1
value = 3

这个例子之所以安全,不是因为数组天生安全,而是因为在访问前明确做了边界检查。

常见错误

  1. 依赖某次运行碰巧得到的“正确结果”,把未定义行为当成正常逻辑继续使用。
  2. 只在 Debug 模式下观察结果,就断定发布版本也会完全一样。
  3. 遇到越界、野指针、释放后访问这类问题时,只修表面现象,不追根因。
  4. 觉得“编译器没报错就说明没问题”,忽略了很多未定义行为本来就未必会在编译期暴露。
  5. 在高优化级别下出现诡异结果时,只怀疑编译器,而不先检查代码是否已经越过语言保证边界。
本文禁止转载
使用 Hugo 构建
主题 StackJimmy 设计 由 Hobin 魔改
最近构建时间:2026-04-17 19:07:48 CST
载入天数...载入时分秒...
发表了 1 篇文章 · 发表了 152 篇笔记 · 总计 18 万 0 千字