取消std :: type_info :: name的结果
我目前正在处理一些日志代码,这些日志代码应该包含关于调用函数的信息。 这应该是相对容易的,标准的C ++有一个type_info
类。 这包含typeid'd类/函数/等的名称。 但是它被破坏了 这不是很有用。 即typeid(std::vector<int>).name()
返回St6vectorIiSaIiEE
。
有没有一种方法可以从中产生有用的东西? 就像上面例子中的std::vector<int>
一样。 如果它只适用于非模板类,那也可以。
解决scheme应该为gcc工作,但是如果我可以移植它将会更好。 这是为了logging,所以它不是很重要,它不能被closures,但它应该有助于debugging。
考虑到这个问题/答案的重要性 ,以及GManNickG的宝贵意见,我已经清理了一些代码。 给出了两个版本:一个具有C ++ 11function,另一个具有C ++ 98function。
在文件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的types: Base*
指点物的types: Derived
在Linux 64位和g ++ 4.7.2(Mingw32,Win32 XP SP2)上用g ++ 4.7.2,g ++ 4.9.0 20140302(实验),clang ++ 3.4(trunk 184647),clang 3.5(trunk 202594)进行testing。
如果您不能使用C ++ 11function,那么在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
(2013年9月8日更新)
被接受的答案(截至2013年9月7日) ,当对abi::__cxa_demangle()
的调用成功时, 返回一个指向本地堆栈分配数组的指针 。
另外请注意,如果你提供了一个缓冲区, abi::__cxa_demangle()
假定它被分配到堆上。 在堆栈上分配缓冲区是一个错误(来自gnu doc): “如果output_buffer
不够长,则使用realloc
扩展。 在指向堆栈的指针上调用realloc()
…哎! (另见Igor Skochinsky的评论。)
您可以轻松validation这两个错误:只需将接受的答案(截至2013年9月7日)的缓冲区大小从1024减小到更小的值,例如16,然后给它一个不超过15的名称(如此realloc()
不被调用)。 不过,根据您的系统和编译器优化,输出将是:垃圾/无/程序崩溃。
要validation第二个错误:将缓冲区大小设置为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; }
这是我们使用的。 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
Boost核心包含一个demangler。 Checkout 核心/ 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
的包装器,正如之前的build议。
在这里,看看type_strings.hpp它包含一个你想要的function。
如果你只是寻找一个demangling工具,你可以用它来破解日志文件中显示的东西,看看binutils附带的c++filt
。 它可以去除C ++和Java符号名称。
不是一个完整的解决scheme,但你可能想看看一些标准(或广泛支持)macros的定义。 logging代码以查看macros的使用是很常见的:
__FUNCTION__ __FILE__ __LINE__ eg: log(__FILE__, __LINE__, __FUNCTION__, mymessage);
它是实现定义的,所以它不是可移植的。 在MSVC ++中,name()是未修饰的名称,您必须查看raw_name()以获取修饰的名称。
在这里黑暗中刺,但在海湾合作委员会,你可能要看看demangle.h
我还发现了一个名为__PRETTY_FUNCTION__
的macros,它可以做到这一点。 它提供了一个漂亮的function名称(图:))。 这是我需要的。
即它给了我以下几点:
virtual bool mutex::do_unlock()
但我不认为它适用于其他编译器。
阿里的解决scheme略有不同。 如果你想要的代码仍然非常相似
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和Ali的解决scheme一样
看看你可以在cxxabi.h
find的cxxabi.h
。
// 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; }
我一直想使用type_info,但是我确信name()成员函数的结果是非标准的,不一定会返回任何可以转换成有意义结果的东西。
如果你坚持一个编译器,可能会有一个编译器特定的function,将做你想要的。 检查文档。