C++ 解开 std::type_info::name 的结果
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/281818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unmangling the result of std::type_info::name
提问by terminus
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
.
我目前正在处理一些日志代码,这些代码应该 - 除其他外 - 打印有关调用函数的信息。这个应该比较容易,标准C++有一个type_info
类。这包含 typeid 的类/函数/等的名称。但它被破坏了。它不是很有用。即typeid(std::vector<int>).name()
返回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.
有没有办法从中产生一些有用的东西?就像std::vector<int>
上面的例子一样。如果它只适用于非模板类,那也没关系。
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 off, but it should be helpful for debugging.
该解决方案应该适用于 gcc,但如果我可以移植它会更好。它用于记录,所以它不是那么重要以至于不能关闭,但它应该有助于调试。
回答by Ali
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.
鉴于这个问题/答案受到的关注,以及来自GManNickG的宝贵反馈,我已经稍微清理了代码。给出了两个版本:一个具有 C++11 特性,另一个只有 C++98 特性。
In file type.hpp
在文件类型.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)
在文件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
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
ptr_base 的Base*
类型:指针对象的类型: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).
在 Linux 64 位和 g++ 4.7.2 (Mingw32, Win32) 上使用 g++ 4.7.2、g++ 4.9.0 20140302(实验)、clang++ 3.4(主干 184647)、clang 3.5(主干 202594)进行测试。
If you cannot use C++11 features, here is how it can be done in C++98, the file type.cppis now:
如果你不能使用 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
(Update from Sep 8, 2013)
(2013 年 9 月 8 日更新)
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.)
接受的答案(截至 2013 年 9 月 7 日),当调用abi::__cxa_demangle()
成功时,返回一个指向本地堆栈分配数组的指针......哎哟!
另请注意,如果您提供缓冲区,则abi::__cxa_demangle()
假定它在堆上分配。在堆栈上分配缓冲区是一个错误(来自 gnu 文档):“如果output_buffer
不够长,则使用 扩展realloc
。” 调用realloc()
指向堆栈的指针......哎哟!(另见Igor Skochinsky 的友好评论。)
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 notlonger than 15 (so realloc()
is notcalled). 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.
您可以轻松验证这两个错误:只需将接受的答案(截至 2013 年 9 月 7 日)中的缓冲区大小从 1024 减小到更小的值,例如 16,并为其命名不超过 15的名称(realloc()
也是不叫)。尽管如此,根据您的系统和编译器优化,输出将是:垃圾/无/程序崩溃。
验证第二个错误:将缓冲区大小设置为 1 并使用名称长于 1 个字符的内容调用它。当您运行它时,程序几乎肯定会崩溃,因为它尝试realloc()
使用指向堆栈的指针进行调用。
(The old answer from Dec 27, 2010)
(2010 年 12 月 27 日的旧答案)
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.
对KeithB 代码所做的重要更改:缓冲区必须由 malloc 分配或指定为 NULL。不要在堆栈上分配它。
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?
我没找到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;
}
回答by moof2k
Boost core contains a demangler. Checkout core/demangle.hpp:
Boost 核心包含一个 demangler。结帐core/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>
}
It's basically just a wrapper for abi::__cxa_demangle
, as has been suggested previously.
abi::__cxa_demangle
正如之前所建议的那样,它基本上只是 的包装器。
回答by KeithB
This is what we use. HAVE_CXA_DEMANGLE is only set if available (recent versions of GCC only).
这是我们使用的。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
回答by Johannes Schaub - litb
Here, take a look at type_strings.hppit contains a function that does what you want.
在这里,看看type_strings.hpp,它包含一个可以执行您想要的功能的函数。
If you just look for a demangling tool, which you e.g. could use to mangle stuff shown in a log file, take a look at c++filt
, which comes with binutils. It can demangle C++ and Java symbol names.
如果您只是寻找一个 demangling 工具,例如,您可以使用它来处理日志文件中显示的内容,请查看c++filt
binutils 附带的 。它可以破坏 C++ 和 Java 符号名称。
回答by luke
Not a complete solution, but you may want to look at what some of the standard (or widely supported) macro's define. It's common in logging code to see the use of the macros:
不是一个完整的解决方案,但您可能想查看一些标准(或广泛支持的)宏的定义。在记录代码中查看宏的使用是很常见的:
__FUNCTION__
__FILE__
__LINE__
e.g.:
log(__FILE__, __LINE__, __FUNCTION__, mymessage);
回答by Eclipse
It's implementation defined, so it's not something that's going to be portable. In MSVC++, name() is the undecorated name, and you have to look at raw_name() to get the decorated one.
Just a stab in the dark here, but under gcc, you might want to look at demangle.h
它是实现定义的,所以它不是可移植的。在 MSVC++ 中,name() 是未修饰的名称,您必须查看 raw_name() 才能获得修饰的名称。
这里只是暗中刺伤,但在 gcc 下,您可能想查看demangle.h
回答by terminus
I also found a macro called __PRETTY_FUNCTION__
, which does the trick. It gives a pretty function name (figures :)). This is what I needed.
我还发现了一个名为 的宏__PRETTY_FUNCTION__
,它可以解决问题。它给出了一个漂亮的函数名称(数字:))。这就是我所需要的。
I.e. it gives me the following:
即它给了我以下内容:
virtual bool mutex::do_unlock()
But I don't think it works on other compilers.
但我认为它不适用于其他编译器。
回答by matzzz
A slight variation on Ali's solution. If you want the code to still be very similar to
阿里的解决方案略有不同。如果您希望代码仍然非常类似于
typeid(bla).name()
,
typeid(bla).name()
,
writing this instead
改写这个
Typeid(bla).name()
(differing only in capital first letter)
Typeid(bla).name()
(仅大写首字母不同)
then you may be interested in this:
那么你可能对此感兴趣:
In file type.hpp
在文件类型.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.cppstays same as in Ali's solution
type.cpp与阿里的解决方案保持一致
回答by Dan Dare
// 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;
}
回答by sancho.s ReinstateMonicaCellio
The accepted solution[1] works mostly well. I found at least one case (and I wouldn't call it a corner case) where it does not report what I expected... with references.
该接受的解决方案[1]作品大多良好。我发现了至少一个案例(我不会称之为极端案例),它没有报告我的预期......带有参考资料。
For those cases, I found another solution, posted at the bottom.
对于这些情况,我找到了另一个解决方案,贴在底部。
Problematic case(using type
as defined in [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;
produces
产生
Type of i is int
Type of ri is int
Solution(using type_name<decltype(obj)>()
, see code below):
解决方案(使用type_name<decltype(obj)>()
,见下面的代码):
cout << "Type of " << "i" << " is " << type_name<decltype(i)>() << endl;
cout << "Type of " << "ri" << " is " << type_name<decltype(ri)>() << endl;
produces
产生
Type of i is int
Type of ri is int&
as desired (at least by me)
根据需要(至少是我)
Code. It has to be in an included header, not in a separately compiled source, due to specialization issues. See undefined reference to template functionfor instance.
代码。由于专业化问题,它必须在包含的头文件中,而不是在单独编译的源代码中。例如,请参阅对模板函数的未定义引用。
#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;
}