开发者生态
morning
C++26:新的调试头文件
摘要
If you’ve ever needed to hit a breakpoint programmatically in C++, you’ve probably written something like this: 1 2 3 4 5 6 7 8 9 #if defined(_MSC_VER) __debugbreak (); #elif defined(__clang__) __buil...
the
defined
and
this
debugger
breakpoint
has
The
three
noexcept
2026-10-17
1 阅读
约6分钟阅读
jandeboevrie
字号:
如果您曾经需要在 C++ 中以编程方式命中断点,您可能会编写如下内容: 1 2 3 4 5 6 7 8 9 #if Defined(_MSC_VER) __debugbreak (); #elif 定义(__clang__) __builtin_debugtrap (); #elif 定义(__GNUC__) && (定义(__i386__) || 定义(__x86_64__)) __asm__ 易失性( "int3" ); #else 引发(SIGTRAP); #endif 每个主要的 C++ 项目都会重新发明这个轮子。 Boost.Test 有 debugger_break() , Catch2 有 CATCH_BREAK_INTO_DEBUGGER , Dear ImGui 有 IM_DEBUG_BREAK() , Unreal 有 UE_DEBUG_BREAK 。所需的平台知识虽然晦涩难懂,但对于工具实施者来说却是众所周知的——它只是没有标准化。感谢 Rene Ferdinand Rivera Morell,C++26 通过 P2546R5 及其配套产品 P2810R4 修复了这个问题。新的 标头提供了三个功能。三个函数 1 2 3 4 5 6 7 #include namespace std { void Breakpoint() noexcept ; bool is_debugger_present () noexcept ;无效breakpoint_if_debugging()noexcept;这三个都是 no except 并且都是独立的。没有一个是 constexpr — 调试是运行时的问题。 std::breakpoint() 无条件断点。当附加调试器时,执行将停止并将控制权交给调试器。在 x86 上,这通常编译为单个 int3 指令。当不存在调试器时,行为是实现定义的 - 在大多数平台上,进程接收信号(例如 SIGTRAP )并将终止,除非捕获到该信号。 std::is_debugger_present() 如果调试器当前正在跟踪程序,则返回 true。每次调用时都会立即执行检查 - 结果不会缓存,因为调试器可以在执行期间随时附加或分离。其底层工作原理因平台而异。例如,在 Windows 上,实现可能会调用 ::IsDebuggerPresent() 。在 Linux 上,GCC 的 libstdc++ 读取 /proc/self/status 并检查 TracerPid 字段。该标准不强制要求任何特定的机制——语义是实现定义的,预期的行为在非规范注释中描述。这个函数的有趣之处在于它是可替换的,就像operator new和operator delete一样。您可以定义自己的版本: 1 2 3 bool std :: is_debugger_present () noexcept { return my_hardware_debug_flag ;这是 P2810R4 引入的,旨在解决独立问题:在裸机平台上,可能没有操作系统级别的方法来检测调试器。如果没有可替换性,该函数要么必须从独立状态中排除(强制#ifdef 随处可见),要么返回无用的默认值。可替换性使您可以将其连接到您的平台提供的任何内容。 std::breakpoint_if_debugging() 大多数用户都会使用的便利函数。它相当于: 1 2 if ( std::is_debugger_present ()) std::breakpoint();连接调试器后,您会遇到断点。如果不是,则什么也不会发生。这是 Catch2、Boost.Test 和所有其他框架手动实现的模式。超越断点 将 is_debugger_present() 作为单独的函数可以实现的不仅仅是条件断点。您可以使用它来: 调试时生成额外的诊断输出 禁用在单步会话期间触发的超时 切换到对调试器更友好的分配器 跳过使调试变得更加困难的优化 关注点的分离是经过深思熟虑的 — breakpoint() 和 is_debugger_present() 是正交的构建块,breakpoint_if_debugging() 是方便的组合。结论 是 C++26 添加的另一个内容,它让您想知道为什么花了这么长时间。平台知识很好理解,每个主要项目都已经有自己的版本,API是三个函数。有时,最有用的标准库添加是最简单的。更深入地联系如果您喜欢这篇文章,请
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱