在编译时(或运行时)获取c ++函数的错误名称

时间:2016-11-25 14:04:59

标签: c++ name-mangling

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

class ValueHolder {

public:
    void printValue ();
} ;

如何在编译时(或运行时)确定其损坏的名称。

例如,我想这样做:

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

此函数可能返回如下字符串:

"_ZN11ValueHolder10printValueEv"

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

我也会接受一个对Gcc& amp; Clang,以及MSVC的存根。

3 个答案:

答案 0 :(得分:9)

根据[lib.type.info]

,没有标准的方法可以做到这一点
  

类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

答案 1 :(得分:3)

我会添加一个答案,但我不会将其标记为正确。它不完整。太大了,无法添加评论。这是我能做的事情,但我正在寻找更好的方法。而且,是的,非常俗气的hacky。但我认为某些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 %s\n", 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);

答案 2 :(得分:-2)

你能做的就是使用g ++编译你的C ++程序并获取.o文件。在如此获得的.o文件上运行'nm'命令以获取受损的名称!这种方法在Linux系统上是可行的。