商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C++如何获取当前函数名和行号 _ 预定义宏与source_location【干货】

C++如何获取当前函数名和行号 _ 预定义宏与source_location【干货】

  发布于2026-07-17 阅读(0)

扫一扫,手机访问

直接说结论:C++20 用 std::source_location 最可靠;老标准只能靠预定义宏(__func____FILE____LINE__),但这些宏本质上是编译器注入的静态字符数组,既不是函数调用,也不能传参或延迟求值,稍不注意就踩坑。下面展开聊聊,到底怎么回事。

为什么 __func__ 不是标准函数,也不能取地址

__func__ 是编译器在每个函数作用域内自动注入的静态字符数组,比如 static const char __func__[] = "foo";。它本质上是个隐含的局部变量,但它的行为很特殊——不能参与常规的表达式求值时机控制。

  • 不能写 &__func__ —— 编译会直接报错:address of function '__func__' cannot be taken。这意味它无法被当作正常变量来取地址或传递。
  • 不能作为参数直接传给模板函数,除非模板显式接受 const char* 且实参处于字面量上下文。普通传参很容易触发编译错误或不预期行为。
  • 最大的陷阱在宏里:__func__ 在宏展开时,始终返回宏定义处的函数名,而不是调用处的函数名。这导致很多人在日志宏里误用,结果打印出来的函数名永远是宏定义所在的那个函数,完全不是预期的。

std::source_location 怎么用才不掉坑

它是 C++20 引入的轻量结构体,通过编译器内置支持生成调用点信息(函数名、文件、行号、列号)。关键点在于:它默认构造时捕获的是调用点,而不是定义点。但前提是——你必须显式调用 ::current() 方法。

  • 必须显式传递,默认不会自动注入。正确写法是:log("msg", std::source_location::current()),别漏掉 ::current()。很多人会写成 std::source_location loc;,然后直接传 loc,结果初始化成无效值,line() == 0function_name() 返回空字符串——白忙一场。
  • 性能几乎无开销:编译期填入常量,不涉及运行时调用或字符串拷贝。这比运行时拼字符串高效得多。
  • 注意编译器版本:MSVC 2019 v16.8+、GCC 10+、Clang 11+ 才完整支持这个特性。低版本可能只返回空字符串或行号 0,调试时务必确认编译环境。
void log(const char* msg, const std::source_location& loc = std::source_location::current()) {    std::cout << loc.file_name() << ":" << loc.line()              << " [" << loc.function_name() << "] " << msg << "\n";}// 调用处自动捕获当前行和函数名log("start processing"); // 输出:main.cpp:42 [main] start processing

预定义宏在日志宏里的典型误用与修复

很多人写日志宏时直接拼接 __FILE____LINE__,却忽略了宏展开时机问题——它们总在宏体内部展开,而不是调用位置。这是个常见的翻车现场。

  • 错误写法:#define LOG(x) std::cerr << __FILE__ << ":" << __LINE__ << x —— 总显示宏定义所在行,而不是调用处。
  • 正确做法:用 __FILE____LINE__ 作为宏参数透传,或改用 std::source_location。如果必须兼容 C++17,可以这样修:#define LOG(x) do { ::log_impl(x, __FILE__, __LINE__, __func__); } while(0),这样宏参数会在调用处展开,获取正确信息。
  • __FUNCTION____PRETTY_FUNCTION__ 是 GCC/Clang 扩展,前者等价于 __func__,后者包含函数签名(如 void foo(int)),但不可移植,跨平台项目慎用。

话说回来,真正麻烦的从来不是“怎么拿到名字”,而是“拿到的是哪一层的名字”——宏、内联、模板实例化、lambda 都会让 __func__source_location 指向意料之外的位置。调试时多打几行 std::source_location::current() 对比,比查文档更快定位问题。

C++如何获取当前函数名和行号 _ 预定义宏与source_location【干货】

本文转载于:https://www.php.cn/faq/2334104.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注