在编译时间(或运行时)获取C 功能的名称

get a c++ function mangled name at compile time (or runtime)

本文关键字:功能 获取 时间 编译 运行时      更新时间:2023-10-16

我有一个函数类方法,valueholder :: printValue

class ValueHolder {
public:
    void printValue ();
} ;

如何在编译时间(或运行时)确定其修理名称。

例如,我想这样做:

const char *mangled_name = GetMangledNameOfSymbol(&ValueHolder::printValue);

此功能可能会返回一个字符串:

"_ZN11ValueHolder10printValueEv"

根据@marco A.先决条件是现代编译器。一个支持TypeID的一个,并打开标志来启用此功能。

我还将接受一个可以在GCC&amp上实用的答案。clang和MSVC的存根。

根据[lib.type.info]

没有标准的方式

类Type_info class type_info描述了实现生成的类型信息。该类的对象有效地存储了指向该类型名称的指针,以及一个适合比较两种类型的平等或整理顺序的编码值。类型的名称,编码规则和整理顺序均未指定,并且在程序之间可能有所不同。

对于您的编译器实现,您可以使用typeid(type/expression).name(),但没有指定或强制执行此名称的装饰(它是实现定义的)。这也取决于所使用的汇编标志(感谢Malat)。

示例:

class ValueHolder {
public:
  void printValue();
};

int main() {
  std::cout << typeid(&ValueHolder::printValue).name();
}

gcc7.0

m11valueholderfvve

clang4.0

m11valueholderfvve

msvc14

void(__cdecl valueholder ::*)(void)__ptr64

我会添加一个答案,但是我不会对其进行正确标记。它还不完整。太大了,无法添加作为评论。这是我可以做的事情,但是我正在寻找一种更好的方式。而且,是的,非常俗气。但是我认为某处有一些API,尽管仍然有点粗糙,但可以保证工作(如果在整个项目中使用单个编译器)。

template<typename R, typename C, typename... A>
struct MemberFunctionPointer
{
    typedef R Return;
    typedef C Class;
};
template<typename R, typename C, typename... A>
constexpr auto inferMemberFunctionPointer(R (C::*method)(A...))
{
    return MemberFunctionPointer<R,C,A...>{};
}
template<typename M, M m, typename... A>
class GenerateMethodSignature
{
    typedef typename decltype(inferMemberFunctionPointer(m))::Class T;
    typedef typename decltype(inferMemberFunctionPointer(m))::Return R;

public:
    static const char *mangledName (const char *fs)
    {
        const char *ts = typeid(T).name();
        const char *rs = typeid(R).name();
        const char *ms = typeid(M).name();
        std::string r = "_Z";
        if (ts[0] != 'N')
            r += "N";
        r += ts;
        if (ts[0] == 'N')
            r.pop_back();
        r += std::to_string(strlen(fs));
        r += fs;
        r += "E";
        r += ms + strlen ("M") + strlen(ts) + strlen ("F") + strlen(rs);
        r.pop_back();
        printf("calculated signature %sn", r.c_str());
        // this is very bad but... for demonstration purposes
        return strdup(r.c_str());
    }
} ;
namespace MyNamespace {
namespace MySubNamespace {
class MyClass
{
public:
    int MyFunction (int myarg);
} ;
} // namespace
} // namespace
#define ExportSignature(T, M) GenerateMethodSignature<decltype(&T::M), &T::M>::mangledName(#M)
const char *myMethodSignature = ExportSignature(MyNamespace::MySubNamespace::MyClass, MyFunction);

好吧,您能做的就是使用G 编译C 程序并获取.o文件。在.o文件上运行" nm"命令,以获取被弄糊的名称!此方法在Linux系统上是可行的。

在理论上的Windows平台运行时,可以使用dbghelp.h/lib

Winapi从函数的地址获取被弄糊的名称

DWORD options = SymGetOptions();
SymSetOptions(options & ~SYMOPT_UNDNAME);
if (SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol))
{
    // etc...
}
SymSetOptions(options);

这将在运行时解析函数名称。但是必须导出该符号(使用__declspec(dllexport)