c++ gcc name-mangling

c++ - Desenredando el resultado de std:: type_info:: name



gcc name-mangling (11)

Aquí, eche un vistazo a type_strings.hpp que contiene una función que hace lo que quiere.

Si solo busca una herramienta de demanda, que podría usar para manipular cosas que se muestran en un archivo de registro, eche un vistazo a c++filt , que viene con binutils. Puede exigir nombres de símbolos C ++ y Java.

Actualmente estoy trabajando en un código de registro que suponía, entre otras cosas, imprimir información sobre la función de llamada. Esto debería ser relativamente fácil, C ++ estándar tiene una clase type_info . Este contiene el nombre de la clase / función / etc typeid. pero está destrozado. No es muy útil. Ie typeid(std::vector<int>).name() St6vectorIiSaIiEE typeid(std::vector<int>).name() devuelve St6vectorIiSaIiEE .

¿Hay alguna manera de producir algo útil a partir de esto? Como std::vector<int> para el ejemplo anterior. Si solo funciona para clases que no son de plantilla, está bien también.

La solución debería funcionar para gcc, pero sería mejor si pudiera portarla. Es para iniciar sesión, por lo que no es tan importante que no se pueda desactivar, pero debería ser útil para la depuración.


Boost core contiene un demangler. Checkout 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> }

Básicamente es solo un contenedor para abi::__cxa_demangle , como se sugirió anteriormente.


Dada la atención que recibe esta pregunta / respuesta, y los valiosos comentarios de GManNickG , he limpiado el código un poco. Se dan dos versiones: una con características C ++ 11 y otra con solo características C ++ 98.

En tipo de archivo.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

En el archivo type.cpp (requiere 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

Uso:

#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; }

Imprime:

Tipo de ptr_base: Base*
Tipo de punta: Derived

Probado con g ++ 4.7.2, g ++ 4.9.0 20140302 (experimental), clang ++ 3.4 (tronco 184647), clang 3.5 (tronco 202594) en Linux 64 bit y g ++ 4.7.2 (Mingw32, Win32 XP SP2).

Si no puede usar las características de C ++ 11, así es como se puede hacer en C ++ 98, el tipo de archivo.cpp ahora es:

#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

(Actualización del 8 de septiembre de 2013)

La respuesta aceptada (a partir del 7 de septiembre de 2013) , cuando la llamada a abi::__cxa_demangle() es exitosa, devuelve un puntero a una matriz asignada de pila local ... ¡ay!
También tenga en cuenta que si proporciona un búfer, abi::__cxa_demangle() asume que se asignará en el montón. La asignación del búfer en la pila es un error (del gnu doc): "Si output_buffer no es lo suficientemente largo, se expande usando realloc ". Llamar a realloc() en un puntero a la pila ... ¡ay! (Véase también el amable comentario de Igor Skochinsky .)

Puede verificar fácilmente estos dos errores: simplemente reduzca el tamaño del búfer en la respuesta aceptada (a partir del 7 de septiembre de 2013) de 1024 a algo más pequeño, por ejemplo 16, y proporciónele algo con un nombre que no sea más de 15 (así realloc() no se llama). Aún así, dependiendo de su sistema y las optimizaciones del compilador, el resultado será: basura / nada / bloqueo del programa.
Para verificar el segundo error: establezca el tamaño del búfer en 1 y llámelo con algo cuyo nombre sea más largo que 1 carácter. Cuando lo ejecuta, el programa casi con seguridad se bloquea cuando intenta llamar a realloc() con un puntero a la pila.

(La vieja respuesta del 27 de diciembre de 2010)

Cambios importantes realizados en el código de KeithB : el buffer debe ser asignado por malloc o especificado como NULL. NO lo asigne en la pila.

Es aconsejable verificar ese estado también.

No HAVE_CXA_DEMANGLE encontrar HAVE_CXA_DEMANGLE . Compruebo __GNUG__ aunque eso no garantiza que el código incluso se compile. Alguien tiene una mejor 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; }


Eche un vistazo a __cxa_demangle que puede encontrar en cxxabi.h .


Esto es lo que usamos. HAVE_CXA_DEMANGLE solo se establece si está disponible (versiones recientes de GCC solamente).

#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


No es una solución completa, pero es posible que desee ver lo que definen algunas de las macros estándar (o ampliamente compatibles). Es común en el código de registro para ver el uso de las macros:

__FUNCTION__ __FILE__ __LINE__ e.g.: log(__FILE__, __LINE__, __FUNCTION__, mymessage);


Siempre he querido usar type_info, pero estoy seguro de que el resultado de la función de miembro name () no es estándar y no necesariamente devolverá nada que se pueda convertir en un resultado significativo.
Si te apegas a un compilador, tal vez haya una función específica del compilador que hará lo que quieras. Verifique la documentación.


Su implementación está definida, por lo que no es algo que pueda ser portátil. En MSVC ++, name () es el nombre no decorado, y debe buscar en raw_name () para obtener el decorado.
Solo una puñalada en la oscuridad aquí, pero bajo gcc, es posible que desee mirar demangle.h


También encontré una macro llamada __PRETTY_FUNCTION__ , que hace el truco. Da un bonito nombre de función (figuras :)). Esto es lo que necesitaba.

Es decir, me da lo siguiente:

virtual bool mutex::do_unlock()

Pero no creo que funcione en otros compiladores.


Una pequeña variación en la solución de Ali. Si quieres que el código siga siendo muy similar a

typeid(bla).name() ,

escribiendo esto en cambio

Typeid(bla).name() (se diferencia solo en mayúscula Typeid(bla).name() )

entonces usted puede estar interesado en esto:

En tipo de archivo.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 se mantiene igual que en la solución de Ali


// 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; }