__LINE__是C++预定义宏,编译期展开为当前行号整型常量,零开销;不可赋值后“动态更新”,须原地使用,常与__FILE__搭配标识源码位置。

用 __LINE__ 宏直接获取当前行号
__LINE__ 是 C++ 标准预定义宏,展开为当前源文件的行号(整型常量),编译期确定,零开销。它不是函数,不能传参或赋值给变量后再“更新”,每次出现都代表它所在那行的编号。
常见误用是试图把它存进变量然后期望后续调用能反映新位置:
int line = __LINE__; // 这里是第 5 行 → line == 5<br> line = __LINE__; // 这里是第 6 行 → 但这一行根本不会执行,line 被重新赋值成 6,不是“动态刷新”
- 只在需要打日志、断言或生成调试信息时原地使用最安全
- 和
__FILE__搭配能构成完整位置标识:std::cout - 注意:宏展开后是纯数字,不带引号,不能直接拼进字符串字面量(比如
"line " __LINE__会编译失败)
封装成函数会丢失真实行号
如果写一个函数如 int get_line() { return __LINE__; },调用它返回的永远是函数体内部那行的行号(比如函数定义在第 10 行,所有调用都返回 10),不是调用点的行号。这是宏和函数的根本区别。
- 想让调用点生效,必须用宏封装:
#define LOG_LINE() __LINE__ - 更实用的是带文件名的宏:
#define WHERE __FILE__, __LINE__,然后用于日志函数参数 - C++20 的
std::source_location可替代,但需显式传参,且调用点要加std::source_location::current()
C++20 std::source_location 的正确用法
std::source_location 是运行时对象,但默认构造函数返回的是调用它的那一行的位置 —— 关键在于它必须作为函数参数,默认值由编译器在调用处注入,不是在函数体内生成。
void log(const char* msg, const std::source_location& loc = std::source_location::current()) {
std::cout << loc.file_name() << ":" << loc.line() << " - " << msg << "\n";
}- 调用
log("hello");时,loc自动捕获调用点(比如main.cpp:23) - 不能写成
auto loc = std::source_location::current(); log("hello", loc);,这样loc记录的是这行代码的位置,不是log调用点 - 兼容性:仅 C++20 起支持,旧项目无法使用
跨平台和调试符号注意事项
__LINE__ 和 __FILE__ 在所有标准编译器(GCC、Clang、MSVC)中行为一致,无需额外配置。但要注意:
立即学习“C++免费学习笔记(深入)”;
-
__FILE__默认展开为相对路径;MSVC 可用/FC编译选项强制绝对路径,GCC/Clang 需依赖构建系统传递-D__FILE__=\"$(realpath $@)\"类似逻辑(不推荐,易出错) - 预处理器宏在宏展开链中可能“跳行”,比如宏定义里含换行,
__LINE__仍指宏调用处,不是宏定义内部 - 发布版若关闭调试信息,
std::source_location依然工作(它不依赖 DWARF/PDB),但__FILE__字符串仍存在,除非被链接器 strip 掉字符串表(极少这么做)
真正容易被忽略的是:行号对模板实例化、宏嵌套、头文件包含深度完全透明 —— 它只认最终展开后的物理行,不是逻辑调用栈。调试时看到的行号,和你在编辑器里数的行,可能因空行、注释、条件编译而不同。


















