__LINE__ 和 __FILE__ 是 C/C++ 标准预定义宏,预处理时直接替换为当前行号和文件路径字符串,无需头文件、无函数调用、零运行时开销。

用 __LINE__ 和 __FILE__ 获取行号和文件名最简单
这两个是 C++(也是 C)标准预定义宏,编译器在预处理阶段就替换成当前源码的行号整数和文件路径字符串。不需要头文件、不调用函数、零运行时开销。
常见写法:
std::cout << "File: " << __FILE__ << ", Line: " << __LINE__ << ' ';
注意:__FILE__ 展开后是字面量字符串(如 "main.cpp"),不是 std::string;__LINE__ 是 int 类型,不是字符串。
为什么 __FILE__ 有时显示绝对路径,有时只显示文件名
取决于编译器如何被调用,以及是否启用了相关选项:
立即学习“C++免费学习笔记(深入)”;
- GCC/Clang 默认输出相对路径(相对于当前工作目录),但若用
-frecord-gcc-switches或某些构建系统(如 CMake 的set(CMAKE_CXX_FLAGS "-g"))可能带完整路径 - MSVC 默认输出完整绝对路径,可用
/FC选项强制为短路径(仅文件名) - 想统一行为?别依赖原始
__FILE__,自己截取最后一段:
const char* basename(const char* path) {
const char* p = strrchr(path, '/');
if (!p) p = strrchr(path, '\');
return p ? p + 1 : path;
}
// 用法:basename(__FILE__)在宏里拼接 __LINE__ 和 __FILE__ 报错?记得字符串化
直接把 __LINE__ 放进字符串字面量会失败,因为它是数字,不是字符串。必须用两次宏展开来“字符串化”:
#define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define AT __FILE__ ":" TOSTRING(__LINE__)
这样 AT 展开后就是类似 "main.cpp":"42" 的字符串字面量(注意中间冒号是手动加的)。漏掉一层宏会导致 TOSTRING(__LINE__) 变成 "__LINE__" 而不是实际数字。
常见错误现象:error: expected primary-expression before ‘:’ token,基本就是没做字符串化。
调试日志里频繁用 __FILE__/__LINE__ 会影响性能吗
不会。它们是编译期常量,所有计算都在预处理阶段完成。但要注意两点:
- 如果把
__FILE__传给需要std::string的日志函数(比如log("msg", __FILE__, __LINE__)),每次都会隐式构造临时std::string—— 这有开销,尤其高频调用时 - 更轻量的做法是传
const char*和int,让日志底层按需格式化(比如用printf风格或fmt::format_to延迟拼接) - Release 构建中,如果日志宏被
#ifdef DEBUG包裹,整个表达式会被彻底剔除,不留痕迹
真正容易被忽略的是跨平台路径分隔符:Linux/macOS 用 /,Windows 用 ,而 __FILE__ 返回的正是源码所在系统的原生格式 —— 别假设它一定是斜杠。


















