鉴于这个问题/答案受到的关注,以及来自GManNickG的宝贵反馈,我已经稍微清理了代码。给出了两个版本:一个具有 C++11 特性,另一个具有 C++98 特性。
在文件类型.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_baseBase*
类型:指针类型:Derived
在 Linux 64 位和 g++ 4.7.2(Mingw32、Win32 XP SP2)上使用 g++ 4.7.2、g++ 4.9.0 20140302(实验性)、clang++ 3.4(主干 184647)、clang 3.5(主干 202594)进行了测试。
如果你不能使用 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
(2013 年 9 月 8 日更新)
接受的答案(截至 2013 年 9 月 7 日),当调用abi::__cxa_demangle()
成功时,返回一个指向本地堆栈分配数组的指针......哎呀!
另请注意,如果您提供缓冲区,abi::__cxa_demangle()
则假定它是在堆上分配的。在堆栈上分配缓冲区是一个错误(来自 gnu 文档):“如果output_buffer
不够长,则使用 . 扩展它realloc
。” 调用realloc()
指向堆栈的指针……哎呀!(另见Igor Skochinsky的善意评论。)
您可以轻松验证这两个错误:只需将已接受答案(截至 2013 年 9 月 7 日)中的缓冲区大小从 1024 减小到更小的值,例如 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;
}