您的位置:首页 >C++ std::source_location::current _ 获取当前行号与文件名【详解】
发布于2026-05-03 阅读(0)
扫一扫,手机访问

问题往往出在理解偏差上。std::source_location::current() 本质上是一个编译期内联函数。它并非在运行时“计算”位置,而是由编译器在宏展开的位置直接注入源码信息。这就意味着,一旦你把它封装进另一个普通函数,位置信息就“定格”了。
来看一个典型的错误封装:
std::source_location get_loc() {
return std::source_location::current(); // ❌ 这里记录的是 get_loc 函数体内的行号(通常是定义该函数的第一行)
}
此时,无论你在哪里调用 get_loc(),它返回的 line() 都指向 get_loc 函数定义体的那一行(通常是第一行),而不是你实际调用的那一行。这是开发者最常踩的坑。
std::source_location::current()。std::source_location 对象作为参数显式传入,并在调用方构造。想让日志函数自动捕获调用位置,标准做法是利用函数的默认参数。编译器会在每个调用点为你自动填充这个参数:
void log(const char* msg, const std::source_location loc = std::source_location::current()) {
printf("[%s:%d] %s\n", loc.file_name(), loc.line(), msg);
}
这样一来,每次你写下 log("error"),参数 loc 就会精准地对应到 log("error") 这行代码所在的文件和行号。
立即学习“C++免费学习笔记(深入)”;
std::source_location::current() 是标准中唯一被允许用作默认参数的“非常量”表达式。auto loc = std::source_location::current(); log("msg", loc); —— 这又掉进了上一节提到的封装陷阱。inline,此方法依然有效。但需要注意,如果函数定义在头文件之外且未标记为 inline,在极少数情况下可能因ODR(单一定义规则)导致不同编译单元中生成不同的位置信息,虽然罕见,但值得留意。std::source_location::file_name() 返回的内容,完全取决于编译器内部是如何记录源文件路径的。这和你编译时使用的 -I 选项、构建系统的工作目录以及源文件的引用方式直接相关。通常,GCC和Clang倾向于输出绝对路径,而MSVC可能更常见相对路径。
strstr(loc.file_name(), "src/")),因为它的表现并不稳定。std::filesystem::path 进行裁剪:std::filesystem::path(loc.file_name()).filename().string()。不仅不会破坏,这恰恰是推荐的做法。宏的优势在于它能确保 current() 在用户代码行直接展开,从而准确捕获位置:
#define LOG(msg) do { \
::log(msg, std::source_location::current()); \
} while(0)
当你调用 LOG("timeout") 时,std::source_location::current() 捕获到的就是 LOG("timeout") 这行宏调用所在的位置。
__func__、日志级别、时间戳等信息。do { ... } while(0) 结构进行包裹是一个稳妥的选择。constexpr 函数进行封装,只要确保函数体是纯内联展开、不引入额外的函数调用层级,也能达到同样效果。一旦封装函数内部产生了实际的函数调用,位置信息就会发生偏移。说到底,真正的难点不在于语法本身,而在于当 source_location 被无意中“抬升”到某个封装层时,你会发现日志中的行号与预期差了那么几行,排查起来却颇为费神。遇到这种情况,首先要检查的就是:是否又多套了一层不必要的函数调用。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9