C++26:新的调试头文件
C++26: The New Debugging Header

原始链接: https://www.sandordargo.com/blog/2026/09/30/cpp26-debugging

C++26 在 `` 头文件中新增了三个 noexcept、freestanding 函数:`std::breakpoint()` 无条件地在调试器下暂停执行;`std::is_debugger_present()` 报告调试器是否已附加,并可为裸机平台替换;`std::breakpoint_if_debugging()` 仅在存在调试器时调用 `breakpoint()`。这标准化了主要 C++ 项目中常用的平台特定调试技巧,还支持更广泛的调试工作流,例如额外诊断或禁用超时。

Hacker News 链接了一篇关于 C++26 新调试头文件的文章。该帖有 111 点和 28 条评论。讨论集中在 breakpoint() 的实现细节,特别是 x86 的 INT3 指令:因为它会触发陷阱并报告下一条指令地址,某些调试器可能把断点位置归错;建议的变通方法是 int3; nop。其他人认为这在 C++ 函数中通常不是问题,且调试器质量各不相同。评论还讨论文章可能由 AI 生成的风格,一些用户批评它是 slop,另一些则辩护或喜欢。其他评论提到 raise(SIGTRAP) 等替代方案、MSVC 实现问题,以及更广泛的 C++ 标准化过程。总体而言,该帖结合了技术调试细节与对文章作者身份的怀疑。
相关文章

原文

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__)
    __builtin_debugtrap();
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
    __asm__ volatile("int3");
#else
    raise(SIGTRAP);
#endif

Every major C++ project reinvents this wheel. Boost.Test has debugger_break(), Catch2 has CATCH_BREAK_INTO_DEBUGGER, Dear ImGui has IM_DEBUG_BREAK() and Unreal has UE_DEBUG_BREAK. The platform knowledge required is arcane but well-known to tooling implementers — it just wasn’t standardized.

C++26 fixes this with P2546R5 and its companion P2810R4 thanks to Rene Ferdinand Rivera Morell. A new <debugging> header provides three functions.

The three functions

1
2
3
4
5
6
7
#include <debugging>

namespace std {
    void breakpoint() noexcept;
    bool is_debugger_present() noexcept;
    void breakpoint_if_debugging() noexcept;
}

All three are noexcept and all three are freestanding. None are constexpr — debugging is a runtime concern.

std::breakpoint()

An unconditional breakpoint. When a debugger is attached, execution halts and control is handed to the debugger. On x86, this typically compiles to a single int3 instruction.

When no debugger is present, the behaviour is implementation-defined — on most platforms the process receives a signal (such as SIGTRAP) and will terminate unless the signal is caught.

std::is_debugger_present()

Returns true if the program is currently being traced by a debugger. The check is performed immediately on each call — the result is not cached because a debugger can attach or detach at any time during execution.

How this works under the hood varies by platform. On Windows, for example, an implementation might call ::IsDebuggerPresent(). On Linux, GCC’s libstdc++ reads /proc/self/status and checks the TracerPid field. The standard doesn’t mandate any particular mechanism — the semantics are implementation-defined, with the intended behaviour described in non-normative notes.

What makes this function interesting is that it’s replaceable, in the same sense as operator new and operator delete. You can define your own version:

1
2
3
bool std::is_debugger_present() noexcept {
    return my_hardware_debug_flag;
}

This was introduced by P2810R4 to solve the freestanding problem: on bare-metal platforms, there may be no OS-level way to detect a debugger. Without replaceability, the function would either have to be excluded from freestanding (forcing #ifdef guards everywhere) or return a useless default. Replaceability lets you wire it to whatever your platform provides.

std::breakpoint_if_debugging()

The convenience function most users will reach for. It’s equivalent to:

1
2
if (std::is_debugger_present())
    std::breakpoint();

When a debugger is attached, you hit a breakpoint. When it’s not, nothing happens. This is the pattern that Catch2, Boost.Test, and every other framework implements manually.

Beyond breakpoints

Having is_debugger_present() as a separate function enables more than just conditional breakpoints. You might use it to:

  • Produce extra diagnostic output when debugging
  • Disable timeouts that would fire during a stepping session
  • Switch to a more debugger-friendly allocator
  • Skip optimizations that make debugging harder

The separation of concerns is deliberate — breakpoint() and is_debugger_present() are orthogonal building blocks, and breakpoint_if_debugging() is the convenience composition.

Conclusion

<debugging> is another one of those C++26 additions that makes you wonder why it took this long. The platform knowledge is well-understood, every major project already has its own version, and the API is three functions. Sometimes the most useful standard library additions are the simplest ones.

Connect deeper

If you liked this article, please

联系我们 contact @ memedata.com