Unmangling性病的结果:: TYPE_INFO ::名Unmangling性病的结果:: T

2019-05-10 10:54发布

我目前正在对所谓的一些日志代码 - 除其他事项外 - 打印有关调用函数的信息。 这应该是比较容易的,标准C ++有type_info类。 这包含typeid'd类/功能/等的名称。 但它的错位。 这不是非常有用的。 即typeid(std::vector<int>).name()返回St6vectorIiSaIiEE

有没有产生有用的从这个东西呢? 像std::vector<int>用于上述示例。 如果它仅适用于非模板类,那也没关系。

该解决方案应适用于海湾合作委员会,但如果我可以将它移植可能会更好。 它是记录,所以它不是那么重要,它不能被关闭,但它应该是调试很有帮助。

Answer 1:

鉴于这个问题/答案备受关注,并从有价值的反馈GManNickG ,我已经清理代码一点点。 两个版本中给出:一个C ++ 11层的功能和另外一个只有C ++ 98的功能。

在文件type.hpp

#ifndef TYPE_HPP
#define TYPE_HPP

#include <string>
#include <typeinfo>

std::string demangle(const char* name);

template <class T>
std::string type(const T& t) {

    return demangle(typeid(t).name());
}

#endif

在文件type.cpp(需要C ++ 11)

#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

std::string demangle(const char* name) {

    int status = -4; // some arbitrary value to eliminate the compiler warning

    // enable c++11 by passing the flag -std=c++11 to g++
    std::unique_ptr<char, void(*)(void*)> res {
        abi::__cxa_demangle(name, NULL, NULL, &status),
        std::free
    };

    return (status==0) ? res.get() : name ;
}

#else

// does nothing if not g++
std::string demangle(const char* name) {
    return name;
}

#endif

用法:

#include <iostream>
#include "type.hpp"

struct Base { virtual ~Base() {} };

struct Derived : public Base { };

int main() {

    Base* ptr_base = new Derived(); // Please use smart pointers in YOUR code!

    std::cout << "Type of ptr_base: " << type(ptr_base) << std::endl;

    std::cout << "Type of pointee: " << type(*ptr_base) << std::endl;

    delete ptr_base;
}

它打印:

ptr_base类型: Base*
指针对象的类型: Derived

使用g ++ 4.7.2测试,克++ 4.9.0 20140302(实验),铛++ 3.4(躯干184647),铛Linux上的64位3.5(躯干202594)和g ++ 4.7.2(MINGW32的Win32 XP SP2)。

如果您不能使用C ++ 11点的功能,这里是它如何可以在C ++ 98来完成,该文件type.cpp现在是:

#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>

struct handle {
    char* p;
    handle(char* ptr) : p(ptr) { }
    ~handle() { std::free(p); }
};

std::string demangle(const char* name) {

    int status = -4; // some arbitrary value to eliminate the compiler warning

    handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );

    return (status==0) ? result.p : name ;
}

#else

// does nothing if not g++
std::string demangle(const char* name) {
    return name;
}

#endif


(从09月08日更新,2013)

接受答案(如2013年9月7日的) ,当调用abi::__cxa_demangle()是成功的, 返回一个指针到本地,堆栈分配数组 ...哎哟!
还要注意的是,如果你提供一个缓冲, abi::__cxa_demangle()假设它是在堆上分配。 在堆栈上分配的缓冲区(从GNU DOC)的错误:“如果output_buffer不够长,它使用扩展realloc 。” 调用realloc()一个指针栈 ......哎哟! (参见伊戈尔Skochinsky的一种评论。)

你可以很容易地验证这两种错误的:是从1024减少缓冲区大小,以接受的答案(如2013年9月7日),以更小的东西,例如16,并给它一个名称超过15(这样的东西realloc() 叫)。 不过,这取决于你的系统和编译器优化上,输出将是:垃圾/无/程序崩溃。
要验证第二个错误:缓冲区的大小设置为1和的东西,其名称是超过1个字符调用它。 当你运行它,程序几乎肯定会崩溃,因为它试图调用realloc()一个指针到堆栈。


(从2010年12月27日旧的答案)

要做出重要的改变KeithB代码 : 缓冲区,必须为通过的malloc分配或指定为NULL。 不分配它的堆栈。

这是明智的检查情况也是如此。

我没能找到HAVE_CXA_DEMANGLE 。 我检查__GNUG__但不保证代码甚至会编译。 任何人有一个更好的主意吗?

#include <cxxabi.h>

const string demangle(const char* name) {

    int status = -4;

    char* res = abi::__cxa_demangle(name, NULL, NULL, &status);

    const char* const demangled_name = (status==0)?res:name;

    string ret_val(demangled_name);

    free(res);

    return ret_val;
}


Answer 2:

Boost睿包含demangler。 结帐核心/ demangle.hpp :

#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <iostream>

template<class T> struct X
{
};

int main()
{
    char const * name = typeid( X<int> ).name();

    std::cout << name << std::endl; // prints 1XIiE
    std::cout << boost::core::demangle( name ) << std::endl; // prints X<int>
}

它基本上只是一个包装abi::__cxa_demangle ,如先前建议。



Answer 3:

这就是我们使用。 HAVE_CXA_DEMANGLE只能设置(如果可用)(最新版本的GCC只)。

#ifdef HAVE_CXA_DEMANGLE
const char* demangle(const char* name)
{
   char buf[1024];
    unsigned int size=1024;
    int status;
    char* res = abi::__cxa_demangle (name,
                                 buf,
                                 &size,
                                 &status);
    return res;
  }
#else
const char* demangle(const char* name)
{
  return name;
}
#endif  


Answer 4:

在这里,看看type_strings.hpp它包含一个函数,你想要做什么。

如果你只是寻找一个demangling工具,例如你可以用它来裂伤在日志文件中显示的东西,看看c++filt ,其自带的binutils。 它可以解码C ++和Java符号名。



Answer 5:

不是一个完整的解决方案,但你可能想看看一些标准的(或广泛支持的)宏的定义。 这是一个在日志代码经常可以看到使用了宏:

__FUNCTION__
__FILE__
__LINE__

e.g.:

log(__FILE__, __LINE__, __FUNCTION__, mymessage);


Answer 6:

这是实现定义,所以它不是那将是便携式的东西。 在MSVC ++,名称()是未修饰的名字,你必须看RAW_NAME()来获得装饰之一。
就在这里黑暗中刺,但在GCC,你可能想看看demangle.h



Answer 7:

我还发现了一个叫宏__PRETTY_FUNCTION__ ,它的伎俩。 它给出了一个漂亮的函数名(图:))。 这正是我需要的。

也就是说,它给了我如下:

virtual bool mutex::do_unlock()

但我不认为它适用于其他的编译器。



Answer 8:

阿里的解决方案稍有不同。 如果你想要的代码仍然是非常相似的

typeid(bla).name()

写这篇代替

Typeid(bla).name()仅在首都首字母不同)

那么你可能感兴趣的是:

在文件type.hpp

#ifndef TYPE_HPP
#define TYPE_HPP

#include <string>
#include <typeinfo>

std::string demangle(const char* name);

/*
template <class T>
std::string type(const T& t) {

  return demangle(typeid(t).name());
}
*/

class Typeid {
 public:

  template <class T>
    Typeid(const T& t) : typ(typeid(t)) {}

  std::string name() { return demangle(typ.name()); }

 private:
  const std::type_info& typ;
};


#endif

type.cpp保持相同阿里的解决方案



Answer 9:

看看__cxa_demangle ,你可以找到在cxxabi.h



Answer 10:

// KeithB's solution is good, but has one serious flaw in that unless buf is static
// it'll get trashed from the stack before it is returned in res - and will point who-knows-where
// Here's that problem fixed, but the code is still non-re-entrant and not thread-safe.
// Anyone care to improve it?

#include <cxxabi.h>

// todo: javadoc this properly
const char* demangle(const char* name)
{
    static char buf[1024];
    size_t size = sizeof(buf);
    int status;
    // todo:
    char* res = abi::__cxa_demangle (name,
                                 buf,
                                 &size,
                                 &status);
    buf[sizeof(buf) - 1] = 0; // I'd hope __cxa_demangle does this when the name is huge, but just in case.
    return res;
  }


Answer 11:

该接受的解决方案 [1]作品大多良好。 我发现至少有一个案例(我不会称之为一个角落的情况下),它不报告我的预期......有引用。

对于这些情况,我找到了另一种解决方案,贴在底部。

有问题的情况下 (使用type如[1]):

int i = 1;
cout << "Type of " << "i" << " is " << type(i) << endl;
int & ri = i;
cout << "Type of " << "ri" << " is " << type(ri) << endl;

产生

Type of i is int
Type of ri is int

溶液 (使用type_name<decltype(obj)>()见下面的代码):

cout << "Type of " << "i" << " is " << type_name<decltype(i)>() << endl;
cout << "Type of " << "ri" << " is " << type_name<decltype(ri)>() << endl;

产生

Type of i is int
Type of ri is int&

根据需要(至少由我)

代码 。 它必须是在包含的头,而不是在一个单独编译的源,由于专业化的问题。 见未定义的参考模板函数的实例。

#ifndef _MSC_VER
#   include <cxxabi.h>
#endif
#include <memory>
#include <string>
#include <cstdlib>

template <class T>
std::string
type_name()
{
    typedef typename std::remove_reference<T>::type TR;
    std::unique_ptr<char, void(*)(void*)> own
           (
#ifndef _MSC_VER
                abi::__cxa_demangle(typeid(TR).name(), nullptr,
                                           nullptr, nullptr),
#else
                nullptr,
#endif
                std::free
           );
    std::string r = own != nullptr ? own.get() : typeid(TR).name();
    if (std::is_const<TR>::value)
        r += " const";
    if (std::is_volatile<TR>::value)
        r += " volatile";
    if (std::is_lvalue_reference<T>::value)
        r += "&";
    else if (std::is_rvalue_reference<T>::value)
        r += "&&";
    return r;
}


Answer 12:

我一直想用TYPE_INFO,但我敢肯定,这个名字()成员函数的结果是非标准不一定返回任何可以被转换成有意义的结果。
如果你坚持一个编译器,有可能会做一个编译器特定的功能,你想要什么。 检查文档。



文章来源: Unmangling the result of std::type_info::name