__LINE__ 和 __func__ 是 C++ 标准内置标识符:前者为当前行号整型常量,后者为隐式声明的 static const char[] 存储函数名;误用 "in " + __func__ 会导致指针加法未定义行为;日志宏应避免副作用,推荐 do { ... } while(0) 封装并传参。

用 __LINE__ 和 __func__ 直接获取行号与函数名
不需要额外库或宏封装,C++ 标准就支持这两个内置标识符:__LINE__ 是整型常量,展开为当前源码行号;__func__ 是隐式声明的 static const char[],值为当前函数名(注意:不是 __FUNCTION__ 或 __PRETTY_FUNCTION__,后者是 GCC 扩展,行为不跨平台)。
常见错误是把 __func__ 当作字符串字面量直接拼接,比如 "in " + __func__ —— 这会触发指针加法而非字符串连接,结果未定义。
- 正确用法:传给接受
const char*的函数(如printf、LOG宏),或用std::string(__func__)构造 - 行号在预处理阶段确定,宏中使用也有效;但若宏被多行展开,
__LINE__返回的是宏调用处的行号,不是宏定义处 -
__func__在类成员函数中只返回函数名(如"foo"),不含类名或参数,和__PRETTY_FUNCTION__有本质区别
封装成日志宏时要注意作用域和求值时机
很多人写 #define LOG() printf("%s:%d %s
", __FILE__, __LINE__, __func__),看似简洁,但实际埋了坑:如果在表达式里多次调用该宏(比如 if (x && LOG(), x > 0)),__LINE__ 会重复展开为同一行,且副作用可能被误判。
- 更安全的做法是让宏带参数并立即求值,例如:
#define LOG_MSG(msg) do { fprintf(stderr, "%s:%d %s - %s ", __FILE__, __LINE__, __func__, msg); } while(0) - 避免在宏里用
std::cout —— 如果__func__所在函数是模板实例化生成的,某些旧编译器(如早期 MSVC)可能生成空字符串 - 若需完整符号信息(含类名、命名空间),必须依赖编译器扩展(如 GCC 的
__PRETTY_FUNCTION__)或调试信息解析(libbacktrace),标准 C++ 不提供
跨平台兼容性差异点:MSVC vs GCC/Clang
__func__ 是 C99/C++11 标准特性,所有现代编译器都支持,但具体值有细微差别。MSVC 默认输出函数名不含修饰,而 GCC/Clang 在启用 RTTI 或调试信息时,__PRETTY_FUNCTION__ 会包含完整签名,但这不属于标准。
- MSVC 下
__func__在 lambda 中返回类似"的占位符,GCC 则可能为空或报错,不能依赖" - Windows 上
__FILE__默认含绝对路径,Linux 常为相对路径,影响日志可读性;可用strrchr(__FILE__, '/')或strrchr(__FILE__, '\')截取文件名 - Clang 在
-fmacro-backtrace-limit=0下仍会限制宏展开深度,过度嵌套的__LINE__可能不准,但日常开发极少触达
运行时无法“动态”获取调用方的行号和函数名
这是最容易误解的一点:__LINE__ 和 __func__ 是编译期常量,只能反映宏/代码所在位置,不是调用栈信息。想拿到「上层调用者」的行号(比如封装一个通用 check(x) 函数并在失败时打印调用处位置),必须靠宏透传:
- 定义
#define CHECK(x) do { if (!(x)) { fprintf(stderr, "%s:%d in %s: check failed ", __FILE__, __LINE__, __func__); } } while(0) - 不能写成
void check(bool x) { ... printf("%s:%d", __FILE__, __LINE__); }—— 这里的__LINE__永远是check函数内部的行号,不是调用它的那行 - 调试场景下,可用
backtrace()+addr2line解析,但开销大、不可移植,且无法直接拿到源码行号字符串
真正需要调用栈语义时,别试图用 __func__ 投机取巧,老实用宏做语法层透传,或者引入专门的诊断库(如 Boost.Stacktrace),否则要么信息错位,要么平台行为分裂。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











