《C++ Primer 第五版》assert 宏 和 NDEBUG 预处理宏变量

发布于:2025-09-05 ⋅ 阅读:(21) ⋅ 点赞:(0)

1. assert 是什么?

  • assert 是 C/C++ 标准库提供的一个调试辅助宏,定义在 <assert.h><cassert>

  • 用法:

    #include <assert.h>
    
    int main() {
        int x = 5;
        assert(x > 0);   // ✅ 条件成立,继续执行
        assert(x < 0);   // ❌ 条件不成立,程序中断
        return 0;
    }
    

工作原理:

  • assert(expr) 会检查 expr 是否为

    • 如果为真 → 什么都不做,继续执行。

    • 如果为假 → 向标准错误输出报错信息(表达式、文件名、行号),并调用 abort() 终止程序。

报错例子:

a.out: test.cpp:5: main: Assertion `x < 0' failed.
Aborted (core dumped)


2. NDEBUG 的作用

NDEBUG 是一个 预处理宏变量,控制 assert 是否生效。

<assert.h> 中(标准库实现),大概长这样:

#ifdef NDEBUG
  #define assert(ignore) ((void)0)
#else
  #define assert(expr) ((expr) ? (void)0 : __assert_fail(...))
#endif

👉 意思是:

  • 没有定义 NDEBUGassert 正常工作。

  • 定义了 NDEBUGassert 会被编译器替换成 (void)0,即什么都不做,彻底失效。


3. 如何启用/禁用 assert

默认情况

  • 一般编译时不定义 NDEBUG,所以 assert 默认是启用的。

禁用 assert(常在 release 模式)

  • 手动在代码里加:

    #define NDEBUG
    #include <assert.h>
    

  • 或者在编译时定义:

    g++ -DNDEBUG main.cpp -o main
    

这样 assert 宏在编译阶段就会被替换掉,不会有任何运行时开销。


4. 使用场景

  • 调试阶段(Debug build):
    assert 来验证程序运行时的“假设”。比如:

    assert(ptr != NULL); // 这里假设指针不为空
    

  • 发布阶段(Release build):
    通常会加 -DNDEBUG 禁用所有 assert,避免:

    • 运行时性能损耗。

    • 在生产环境因为 assert 崩掉服务。


5. 注意点

  1. assert 不适合替代正常的错误处理逻辑。

    • Debug 模式下崩溃方便开发者发现问题。

    • Release 模式下它可能被编译掉,完全没效果。
      👉 所以不要拿 assert 来检查用户输入、网络异常等情况。

  2. 如果你想 即使在 Release 也强制检查,就写自己的检查逻辑:

     
    if (!ptr) {
        fprintf(stderr, "fatal: null pointer\n");
        exit(1);
    }
    


6. 比喻

  • assert 就像你写代码时的“安全带”,确保某个假设为真,否则立刻报警停车。

  • NDEBUG 就像把安全带“剪掉”,让车可以随便跑,不会因为警报停下来。

    • 调试阶段:戴上安全带,保护自己。

    • 发布阶段:去掉安全带,车能跑得更快,但要自己负责。


✅ 总结:

  • assert(expr):调试时验证假设,失败就中断。

  • NDEBUG:编译开关,定义后会让所有 assert 失效。

  • 用法:调试阶段开着,发布阶段关掉。