跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

C++中std::source_location怎么打印代码行号_C++20日志调试技巧【备忘】

最常用写法是定义宏LOG_LINE()调用std::source_location::current(),日志函数按值接收默认参数;不可取地址或绑定引用,因返回纯右值;跨平台需校验line()==1且file_name()为空时回退。
std::source_location
本身不支持直接打印,必须显式调用
line()
、
file_name()
等成员函数才能拿到行号等信息;它只是个轻量值类型,不是格式化工具。 怎么在日志里自动捕获当前行号和文件名 最常用写法是定义一个宏,把
std::source_location::current()
的调用“固定”在调用点展开:
#define LOG_LINE() std::source_location::current()
然后在日志函数中接收该参数(默认值避免每个调用都手动传):
void log(const char* msg, std::source_location loc = std::source_location::current()) { printf("[%s:%d] %s\n", loc.file_name(), loc.line(), msg); }
调用时直接
log("user logged in")
就能打出真实调用处的行号——因为宏没参与,
std::source_location::current()
是在调用点编译期求值的。 立即学习 “ C++免费学习笔记(深入) ”; C知道 CSDN推出的一款AI技术问答工具 下载 为什么不能直接传 &std::source_location::current() 常见错误是试图取地址或绑定引用:
auto& loc = std::source_location::current();
—— 错,返回的是纯右值,引用绑定失败(GCC/Clang 报错
cannot bind non-const lvalue reference to an rvalue
)
const auto& loc = ...
—— 虽然语法通过,但会延长临时对象生命周期,行为不可靠;不同编译器优化下可能捕获到宏展开位置而非真实调用点 正确做法永远是按值传递
std::source_location
,它只有 4 个
size_t
成员,开销极小 MSVC、GCC、Clang 对 __builtin_SOURCE_LOCATION 的兼容差异 C++20 标准接口统一,但底层实现依赖编译器扩展: Clang/GCC:基于
__builtin_SOURCE_LOCATION
,需开启
-std=c++20
且不加
-fno-builtin
MSVC:从 19.30(VS 2022 17.0)起原生支持,但旧版(如 VS 2019)即使开 C++20 也不支持,会静默回退为默认构造值(
line() == 1
,
file_name() == ""
) 跨平台项目建议加运行时校验:
if (loc.line() == 1 && std::string_view(loc.file_name()).empty()) { /* fallback */ }
注意:
std::source_location::current()
的值完全由编译器在翻译单元内填充,无法被宏、内联函数或模板推导干扰——但如果你把它藏在中间函数里(比如封装一层再转发),那拿到的就是那一层的行号,不是原始调用点。想保真,就得让
current()
出现在最终日志调用的同一行。这是最容易忽略、也最难调试的点。

相关文章