c++oding="utf-8" ?>
__file__ 和 __line__ 是编译器内置宏,分别展开为当前源文件路径(const char*)和行号(int),无运行时开销;误写为 __file__() 会编译失败,因非函数。

__FILE__ 和 __LINE__ 是最直接的解决方案
编译器内置宏 __FILE__ 和 __LINE__ 在预处理阶段就被替换成当前源文件的绝对路径(或相对路径,取决于编译器和构建配置)和行号。它们不是函数调用,不产生运行时开销,也不依赖任何头文件。
常见错误是误以为它们是 C++ 标准库函数,试图加括号调用:__FILE__() 或 __LINE__() —— 这会编译失败,因为它们是宏,不是函数。
-
__FILE__类型是const char*,内容由编译器决定;MSVC 默认输出相对路径,GCC/Clang 默认输出绝对路径(可通过-frecord-gcc-switches或构建系统控制) -
__LINE__是整型常量,类型为int,值在每一行唯一且静态确定 - 二者在宏展开中可安全拼接,比如用于日志前缀:
"["
需要字符串字面量拼接时,用 #define 包一层更可靠
直接在函数参数里用 __FILE__ 和 __LINE__ 一般没问题,但若想构造固定格式的调试字符串(如 "file.cpp:123"),不能直接用 __FILE__ ":" __LINE__ —— 字符串字面量拼接只对相邻字符串字面量有效,而 __LINE__ 是数字,无法自动转成字符串。
正确做法是用宏做字符串化:
#define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define LOCATION __FILE__ ":" TOSTRING(__LINE__)
这样 LOCATION 展开后就是类似 "src/main.cpp:42" 的 const char* 字面量。注意:如果文件名含空格或特殊字符,某些旧版编译器可能出问题,但现代 GCC/Clang/MSVC 均支持。
std::source_location(C++20)更适合封装和复用
如果你用的是 C++20 或更新标准,std::source_location 是类型安全、可拷贝、可传参的替代方案,比宏更灵活,尤其适合写通用日志函数:
void log(const std::string& msg,
const std::source_location& loc = std::source_location::current()) {
std::cout <p>关键点:</p>
- 必须显式启用 C++20(
-std=c++20),否则std::source_location不可用 -
loc.file_name()返回const char*,内容通常比__FILE__更简洁(如仅文件名,不含路径),具体行为由实现定义;GCC 返回相对路径,MSVC 默认返回文件名 - 默认参数
std::source_location::current()在调用点求值,不是在函数定义处 —— 这是它和宏的本质区别,也是优势所在 - 性能几乎无损:主流实现将其作为编译期常量嵌入,不增加运行时负担
跨平台日志宏里混用宏和 source_location 容易出错
有人试图写一个“兼容 C++17 和 C++20”的日志宏,比如:
#ifdef __cpp_lib_source_location
log(msg, std::source_location::current());
#else
log(msg, __FILE__, __LINE__);
#endif
这看似合理,但实际容易踩坑:
- 函数重载歧义:如果
log有两个重载版本(一个接受std::source_location,一个接受const char*, int),编译器可能因 SFINAE 或 ADL 规则选错重载 - 宏展开时机问题:
__FILE__和__LINE__在宏定义处展开,而非调用处 —— 如果宏里再套一层宏,位置信息可能错位 - MSVC 对
__cpp_lib_source_location的检测不严格,某些版本即使开了 /std:c++20 也不定义该宏,导致回退逻辑失效
更稳妥的做法是:明确项目使用的 C++ 标准,统一采用一种机制。如果必须兼容,优先用 __FILE__/__LINE__ + 自定义结构体封装,避免混合范式。
真正麻烦的不是获取位置本身,而是不同场景下对“文件名粒度”和“调用栈深度”的隐含需求 —— 比如单元测试框架要精确到 test 函数入口,而崩溃日志可能需要完整路径。这些得靠上层逻辑判断,__FILE__ 和 std::source_location 都只提供最基础的单点信息。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











