Why does typeid.name() return weird characters using GCC and how to make it print unmangled names?
The return of name
is implementation defined : an implementation is not even required to return different strings for different types.
What you get from g++ is a decorated name, that you can "demangle" using the c++filt
command or __cxa_demangle
.
typeid() returns extra characters in g++
Because it is a pointer to foo. And foo has 3 characters. So it becomes P3foo
. The other one has type foo
, so it becomes 3foo
. Note that the text is implementation dependent, and in this case GCC just gives you the internal, mangled name.
Enter that mangled name into the program c++filt
to get the unmangled name:
$ c++filt -t P3foo
foo*
Unmangling the result of std::type_info::name
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;
}
Strange behaviour of the typeid operator?
What's going on is nothing special. Just that typeid
doesn't promise to return the "original" name of the type, but just a name.
The function returns an implementation-defined string, which, if you're lucky, is recognizable, but it makes no promise of that.
Getting incorrect class name when using typeid -
There is no requirement on what type_info::name()
looks like.
The result of a
typeid
expression is an lvalue of static typeconst std::type_info
(18.7.1) and dynamic type
const std::type_info
orconst name
where name is an implementation-defined class publicly derived from
std::type_info
Then, about std::type_info::name()
:
const char* name() const;
Returns: an implementation-defined NTBS.
[...]
NTBS is simply a shorthand for null-terminated byte string.
In other words: You should not rely on any value of type_info::name()
.
What you actually see with g++:
Those names are mangled names, and g++'s implementation of such mangled names is based on length-prefixed strings, where each substring is the namespace name, plus some other info; but that's basically it.
For example:
unmangled: foo::bar::Frob
mangled: 3foo3bar4Frob
Example to put into your compiler:
#include <iostream>
#include <typeinfo>
namespace foo { namespace bar {
enum Frob {};
class Frobnicate {};
Frob frob;
template <typename T> void Meh() { throw T(); }
} }
int main () {
std::cout << typeid(foo::bar::Frob).name() << '\n'
<< typeid(foo::bar::Frobnicate).name() << '\n'
<< typeid(foo::bar::frob).name() << '\n'
<< typeid(foo::bar::Meh<int>).name() << '\n'
<< typeid(foo::bar::Meh<float>).name() << '\n'
;
}
Output for me:
N3foo3bar4FrobE
N3foo3bar10FrobnicateE
N3foo3bar4FrobE
FvvE
FvvE
The latter two show you that one even cannot rely on names being different.
What does PKc , as the output of typeid(var).name(), mean?
PKc
is the mangled name of const char*
. P
is the encoding for "pointer", K
refers to "const", and c
means "char".
See also Why does typeid.name() return weird characters using GCC and how to make it print unmangled names?.
How can I get the data type for boost::any variable?
You need to use boost::any
's member function type()
which returns a const std::type_info&
of the contained value
cout << "num1.type().name(): " << num1.type().name() << endl;
Related Topics
Why Is the Size of an Empty Class in C++ Not Zero
Destruction Order of Static Objects in C++
Returning Arrays from a Function in C++
What Is a Subnormal Floating Point Number
Templates: Parent Class Member Variables Not Visible in Inherited Class
Difference Between Erase and Remove
Erasing from a Std::Vector While Doing a For Each
Advantages of Using Std::Make_Unique Over New Operator
Are Variable Length Arrays There in C++
Is This Key-Oriented Access-Protection Pattern a Known Idiom
Gdb Complaining About Missing Raise.C
C++11 Features in Visual Studio 2012
Initializing Fields in Constructor - Initializer List VS Constructor Body
Difference in Floating Point Arithmetics Between X86 and X64