unmangling std :: type_info :: name的结果 [英] Unmangling the result of std::type_info::name

查看:442
本文介绍了unmangling std :: type_info :: name的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在处理一些日志代码,除了别的以外,打印关于调用函数的信息。这应该比较容易,标准C ++有一个 type_info 类。这包含了typeid的类/函数/等的名称。但它的损坏。这不是很有用。也就是说 typeid(std :: vector< int>)。name()返回 St6vectorIiSaIiEE



有没有办法生产一些有用的东西?像上面的例子的 std :: vector< int> 。如果它只适用于非模板类,这也很好。



解决方案应该适用于gcc,但如果我可以移植它会更好。

解决方案

这是一个非常重要的事情,考虑到此问题/答案收到的关注,以及来自 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

.cpp (需要C ++ 11)

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

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

int status = -4; //一些任意值以消除编译器警告

//通过将标志-std = c ++ 11传递给g ++
来启用c ++ 11 std :: unique_ptr< char,void (*)(void *)> res {
abi :: __ cxa_demangle(name,NULL,NULL,& status),
std :: free
};

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

#else

//如果没有则不做任何操作g ++
std :: string demangle(const char * name){
返回名称;
}

#endif

用法:

  #include< iostream> 
#includetype.hpp

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

struct派生的:public Base {};

int main(){

Base * ptr_base = new Derived(); //请在您的代码中使用智能指针!

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

std :: cout<< 委托类型:< type(* ptr_base)<< std :: endl;

delete ptr_base;
}

打印:



ptr_base的类型: Base *

委托类型:派生



在Linux 64位和g ++ 4.7.2上测试g ++ 4.7.2,g ++ 4.9.0 20140302(实验),clang ++ 3.4(trunk 184647),clang 3.5(trunk 202594)如果你不能使用C ++ 11的功能,这里是如何可以在C ++ 98中完成,文件

type.cpp 现在是:

  #includetype.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; //一些任意值,以消除编译器警告

句柄结果(abi :: __ cxa_demangle(name,NULL,NULL,& status));

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

#else

//如果没有则不做任何操作g ++
std :: string demangle(const char * name){
返回名称;
}

#endif









(更新日期:2013年9月8日)



接受的答案(截至2013年9月7日),当调用 abi :: __ cxa_demangle()成功,返回指向本地堆栈分配的数组的指针 ... uch!

另外请注意,如果你提供一个缓冲区, abi :: __ cxa_demangle()假定它在堆上分配。在堆栈上分配缓冲区是一个错误(从gnu doc):如果 output_buffer 不够长,它使用 (另请参见 Igor Skochinsky 的实物评论。)



您可以轻松验证这两个错误:只需将接受答案(2013年9月7日)的缓冲区大小从1024减小到更小,例如16,然后给出它的名称​​不是长于15(因此 realloc()不是被调用)。仍然,根据您的系统和编译器优化,输出将是:garbage / nothing /程序崩溃。

要验证第二个错误:将缓冲区大小设置为1,并调用它的名称为长于1个字符。当你运行它,程序几乎肯定崩溃,因为它试图调用 realloc()与指向堆栈的指针。






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



KeithB的代码缓冲区必须由malloc分配或指定为NULL。不要



我无法找到

code> 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);

免费(res);

return ret_val;
}


I'm currently working on some logging code that supposed to - among other things - print information about the calling function. This should be relatively easy, standard C++ has a type_info class. This contains the name of the typeid'd class/function/etc. but it's mangled. It's not very useful. I.e. typeid(std::vector<int>).name() returns St6vectorIiSaIiEE.

Is there a way to produce something useful from this? Like std::vector<int> for the above example. If it only works for non-template classes, that's fine too.

The solution should work for gcc, but it would be better if I could port it. It's for logging so it's not so important that it can't be turned of, but it should be helpful for debugging.

解决方案

Given the attention this question / answer receives, and the valuable feedback from GManNickG, I have cleaned up the code a little bit. Two versions are given: one with C++11 features and another one with only C++98 features.

In file 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

In file type.cpp (requires 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

Usage:

#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;
}

It prints:

Type of ptr_base: Base*
Type of pointee: Derived

Tested with g++ 4.7.2, g++ 4.9.0 20140302 (experimental), clang++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) on Linux 64 bit and g++ 4.7.2 (Mingw32, Win32 XP SP2).

If you cannot use C++11 features, here is how it can be done in C++98, the file type.cpp is now:

#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



(Update from Sep 8, 2013)

The accepted answer (as of Sep 7, 2013), when the call to abi::__cxa_demangle() is successful, returns a pointer to a local, stack allocated array... ouch!
Also note that if you provide a buffer, abi::__cxa_demangle() assumes it to be allocated on the heap. Allocating the buffer on the stack is a bug (from the gnu doc): "If output_buffer is not long enough, it is expanded using realloc." Calling realloc() on a pointer to the stack... ouch! (See also Igor Skochinsky's kind comment.)

You can easily verify both of these bugs: just reduce the buffer size in the accepted answer (as of Sep 7, 2013) from 1024 to something smaller, for example 16, and give it something with a name not longer than 15 (so realloc() is not called). Still, depending on your system and the compiler optimizations, the output will be: garbage / nothing / program crash.
To verify the second bug: set the buffer size to 1 and call it with something whose name is longer than 1 character. When you run it, the program almost assuredly crashes as it attempts to call realloc() with a pointer to the stack.


(The old answer from Dec 27, 2010)

Important changes made to KeithB's code: the buffer has to be either allocated by malloc or specified as NULL. Do NOT allocate it on the stack.

It's wise to check that status as well.

I failed to find HAVE_CXA_DEMANGLE. I check __GNUG__ although that does not guarantee that the code will even compile. Anyone has a better idea?

#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;
}

这篇关于unmangling std :: type_info :: name的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆