C++中如何获取指向当前正在执行函数的self函数指针
C++ 获取当前执行函数唯一标识的实现方案
标准C++没有提供直接获取当前执行函数自身指针的内置语法,但是针对你做日志唯一标识的需求,有成熟的可实现方案:
方案1:C++20 std::source_location(推荐,跨平台)
这是C++标准提供的专门用于获取代码位置信息的工具,不仅可以生成唯一标识,还能直接获取函数名、文件名、行号等日志常用信息,完全不需要你手动获取函数指针:
#include <source_location> #include <cstdio> #include <cassert> // 日志宏示例 #define LOG_INFO(msg) do { \ const auto& loc = std::source_location::current(); \ // 用函数名字符串的地址作为唯一标识,和函数指针效果完全一致,比对效率相同 const void* unique_id = reinterpret_cast<const void*>(loc.function_name()); \ printf("[ID: %p] %s:%d %s: %s\n", unique_id, loc.file_name(), loc.line(), loc.function_name(), msg); \ } while(0) void foo() { LOG_INFO("test log"); // 同一函数内多次调用获取的unique_id完全一致 const auto loc1 = std::source_location::current(); const auto loc2 = std::source_location::current(); assert(reinterpret_cast<const void*>(loc1.function_name()) == reinterpret_cast<const void*>(loc2.function_name())); }
该方案完全符合C++标准,所有主流编译器(GCC 8+、Clang 9+、MSVC 2019 16.6+)都已经支持,不需要依赖编译器私有扩展。
方案2:兼容旧标准的编译器扩展方案
如果你的项目还不能升级到C++20,可以用主流编译器都支持的函数名字符串宏实现同样的效果:
- GCC/Clang 用
__PRETTY_FUNCTION__,MSVC 用__FUNCDNAME__,这两个宏展开的是当前函数的唯一签名字符串,同一函数的字符串地址是固定的,可以直接作为唯一标识使用:
#include <cstdio> #include <cassert> // 跨编译器统一函数签名宏 #if defined(_MSC_VER) #define FUNC_SIGNATURE __FUNCDNAME__ #elif defined(__GNUC__) || defined(__clang__) #define FUNC_SIGNATURE __PRETTY_FUNCTION__ #else #define FUNC_SIGNATURE __func__ #endif // 日志宏示例 #define LOG_INFO(msg) do { \ const void* unique_id = reinterpret_cast<const void*>(FUNC_SIGNATURE); \ printf("[ID: %p] %s:%d %s: %s\n", unique_id, __FILE__, __LINE__, FUNC_SIGNATURE, msg); \ } while(0) void foo() { LOG_INFO("test log"); assert(reinterpret_cast<const void*>(FUNC_SIGNATURE) == reinterpret_cast<const void*>(FUNC_SIGNATURE)); }
该方案兼容C++11甚至更早的标准,适用范围更广。
关于直接获取函数指针的说明
如果你一定要实现示例中assert(<self-pointer> == &foo)的效果,目前没有通用的标准C++实现方式,仅能通过特定平台的符号解析、内联汇编等hack方式实现,可移植性很差,对于日志需求来说完全没有必要,上面两种方案已经可以完全满足你的唯一标识需求,性能和使用函数指针没有差异。
内容的提问来源于stack exchange,提问作者Nikita Demodov
相关产品推荐
相关产品推荐

