我目前正在研究一些日志代码,它们应该 - 除其他外 - 打印有关调用函数的信息.这应该相对容易,标准C++有一个type_info
类.它包含typeid'd类/函数/ etc的名称.但它被破坏了.它不是很有用.即typeid(std::vector
回归St6vectorIiSaIiEE
.
有没有办法从中产生有用的东西?就像std::vector
上面的例子一样.如果它只适用于非模板类,那也没关系.
该解决方案应该适用于gcc,但如果我可以移植它会更好.这是为了记录所以它不是那么重要,它不能被关闭,但它应该有助于调试.
鉴于这个问题/答案得到了关注,以及来自GManNickG的有价值的反馈,我已经清理了一些代码.给出了两个版本:一个具有C++ 11特性,另一个仅具有C++ 98特性.
在文件type.hpp中
#ifndef TYPE_HPP
#define TYPE_HPP
#include
#include
std::string demangle(const char* name);
template
std::string type(const T& t) {
return demangle(typeid(t).name());
}
#endif
在文件type.cpp中(需要C++ 11)
#include "type.hpp"
#ifdef __GNUG__
#include
#include
#include
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 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
#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
#include
#include
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的善意评论.)
你可以很容易地验证这两种错误的:是从1024减少缓冲区大小,以接受的答案(如2013年9月7日),以更小的东西,例如16,并给它一个名字的东西不超过15(因此realloc()
是不叫).仍然,根据您的系统和编译器优化,输出将是:garbage/nothing/program crash.
要验证第二个错误:将缓冲区大小设置为1并使用名称长度超过1个字符的内容调用它.当你运行它时,程序几乎肯定会在尝试realloc()
使用指向堆栈的指针进行调用时崩溃.
(2010年12月27日的旧答案)
对KeithB代码进行的重要更改:缓冲区必须由malloc分配或指定为NULL.不要在堆栈上分配它.
检查这种状态也是明智之举.
我没找到HAVE_CXA_DEMANGLE
.我检查__GNUG__
虽然不能保证代码甚至可以编译.谁有更好的主意?
#include
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;
}
Boost核心包含一个demangler.结帐core/demangle.hpp:
#include#include #include template struct X { }; int main() { char const * name = typeid( X ).name(); std::cout << name << std::endl; // prints 1XIiE std::cout << boost::core::demangle( name ) << std::endl; // prints X }
它基本上只是一个包装器abi::__cxa_demangle
,正如之前所建议的那样.
这就是我们使用的.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
在这里,看一下type_strings.hpp,它包含一个可以完成你想要的功能.
如果您只是寻找一个demangling工具,您可以使用它来破坏日志文件中显示的内容,请查看c++filt
binutils附带的内容.它可以解析C++和Java符号名称.