Compte tenu de l'attention que cette question / réponse reçoit et des précieux commentaires de GManNickG , j'ai un peu nettoyé le code. Deux versions sont proposées: une avec des fonctionnalités C ++ 11 et une autre avec uniquement des fonctionnalités C ++ 98.
Dans le fichier 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
Dans le fichier type.cpp (nécessite 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;
}
Il imprime:
Type de ptr_base: Base*
Type de pointee:Derived
Testé avec g ++ 4.7.2, g ++ 4.9.0 20140302 (expérimental), clang ++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) sous Linux 64 bits et g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Si vous ne pouvez pas utiliser les fonctionnalités C ++ 11, voici comment cela peut être fait en C ++ 98, le fichier type.cpp est maintenant:
#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
(Mise à jour du 8 septembre 2013)
La réponse acceptée (au 7 septembre 2013) , lorsque l'appel à abi::__cxa_demangle()
réussit, renvoie un pointeur vers un tableau local alloué par pile ... aïe!
Notez également que si vous fournissez un tampon, abi::__cxa_demangle()
suppose qu'il est alloué sur le tas. Allouer le tampon sur la pile est un bogue (de la doc gnu): "Si ce output_buffer
n'est pas assez long, il est développé avec realloc
." Appel realloc()
d'un pointeur vers la pile ... aïe! (Voir aussi Igor Skochinsky commentaire aimable d' .)
Vous pouvez facilement vérifier ces deux bogues: réduisez simplement la taille de la mémoire tampon dans la réponse acceptée (à partir du 7 septembre 2013) de 1024 à quelque chose de plus petit, par exemple 16, et donnez-lui quelque chose avec un nom ne dépassant pas 15 (ainsi realloc()
est pas appelé). Pourtant, en fonction de votre système et des optimisations du compilateur, la sortie sera: garbage / rien / programme crash.
Pour vérifier le deuxième bogue: définissez la taille de la mémoire tampon sur 1 et appelez-la avec quelque chose dont le nom est plus long que 1 caractère. Lorsque vous l'exécutez, le programme se bloque presque assurément lorsqu'il tente d'appeler realloc()
avec un pointeur vers la pile.
(L'ancienne réponse du 27 décembre 2010)
Modifications importantes apportées au code de KeithB : le tampon doit être soit alloué par malloc, soit spécifié comme NULL.Ne l'allouez PAS sur la pile.
Il est également sage de vérifier ce statut.
Je n'ai pas réussi à trouver HAVE_CXA_DEMANGLE
. Je vérifie __GNUG__
même si cela ne garantit pas que le code sera même compilé. Quelqu'un a une meilleure idée?
#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;
}
#include <cxxabi.h>
. Sinon, a très bien fonctionné, merci.