通八洲科技

c++中的std::source_location和__FILE__/__LINE__有什么区别_c++现代日志与调试【C++20】

日期:2025-12-23 00:00 / 作者:裘德小鎮的故事
std::source_location 是 C++20 引入的类型安全运行时类类型,自动捕获调用点的文件名、行号、列号和函数名,支持成员函数访问,常作带默认值的函数参数。

std::source_location 是类型安全的运行时对象

std::source_location 是 C++20 引入的标准库类型,它在调用点(通常是函数入口)自动构造一个包含文件名、行号、列号和函数名的结构化对象。它不是宏,而是一个可传递、可拷贝、可存储的类类型,支持成员函数如 file_name()line()column()function_name()

典型用法是作为函数默认参数:

void log(const std::string& msg, 
         const std::source_location& loc = std::source_location::current()) {
    std::cerr << "[" << loc.file_name() << ":" << loc.line() 
              << "] " << msg << "\n";
}

调用 log("error occurred") 时,编译器自动填入**实际调用处**的位置信息,而非定义处 —— 这对封装日志函数至关重要。

__FILE__/__LINE__ 是预处理宏,无类型、无作用域控制

__FILE____LINE__ 是传统 C 风格的预处理器宏,在预处理阶段被文本替换为字面量字符串和整数。它们不经过类型检查,不能直接参与模板推导或作为类成员;且一旦写在某个函数/宏定义里,展开后固定指向该定义位置,无法反映调用点。

例如:

#define LOG(msg) std::cerr << __FILE__ << ":" << __LINE__ << " " << msg << "\n"
void foo() { LOG("in foo"); } // 输出的是 LOG 宏定义所在行,不是 foo() 中这行

除非手动传参(如 LOG("msg", __FILE__, __LINE__)),否则容易误标位置 —— 尤其在封装层中极易出错。

关键差异总结

现代日志实践中推荐组合使用

不必非此即彼。常见稳健做法是:

基本上就这些 —— 不复杂但容易忽略细节。C++20 的 source_location 让“在哪出的问题”这件事,终于有了标准、干净、靠谱的答案。