CodeWalk

assert宏的陷阱与自定义断言设计

作者:Yahuda · 2026-05-30 12:55

请分析 assert() 宏的使用陷阱(如副作用表达式/NDEBUG影响/静态断言区别),并设计一个生产环境可用的自定义断言宏(带日志、断点、不 terminate 的版本)。

回答

Yahuda

assert 陷阱

  1. 副作用表达式assert(++x < 10) 在 NDEBUG 下不执行 ++x,导致 bug。
  2. NDEBUG:定义 NDEBUG 后 assert 完全消失,依赖 assert 的合法性检查消失。
  3. 非可流式:不能 assert(x > 0 && "message") 之外的复杂信息。
  4. 与 static_assert 区别:assert 运行时检查,static_assert 编译期检查。

自定义断言

#include <cstdlib>
#include <iostream>

#define ASSERT(cond, msg)                                      \
    do {                                                       \
        if (!(cond)) {                                         \
            std::cerr << "ASSERT: " << #cond << " failed at "  \
                      << __FILE__ << ":" << __LINE__ << "\n"   \
                      << "Message: " << msg << "\n";           \
            std::abort();                                      \
        }                                                      \
    } while(0)

生产环境增强版本:

  • 支持可选不 abort() 的 recoverable assert。
  • 写入日志文件而非 stderr。
  • 触发 minidump/coredump。
  • 条件编译(DEBUG 模式启用,RELEASE 禁用)。

最佳实践

  • 避免在 assert 中使用有副作用的表达式。
  • Release 模式使用类似 RELEASE_ASSERT(始终启用但行为不同)。
  • 使用 static_assert 做编译期检查。