Biorąc pod uwagę uwagę , jaką wzbudza to pytanie / odpowiedź, oraz cenne opinie od GManNickG , trochę wyczyściłem kod. Podano dwie wersje: jedną z funkcjami C ++ 11 i drugą z funkcjami C ++ 98.
W pliku 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
W pliku type.cpp (wymaga C ++ 11)
#include "type.hpp"
#ifdef __GNUG__
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
std::string demangle(const char* name) {
int status = -4;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
#else
std::string demangle(const char* name) {
return name;
}
#endif
Stosowanie:
#include <iostream>
#include "type.hpp"
struct Base { virtual ~Base() {} };
struct Derived : public Base { };
int main() {
Base* ptr_base = new Derived();
std::cout << "Type of ptr_base: " << type(ptr_base) << std::endl;
std::cout << "Type of pointee: " << type(*ptr_base) << std::endl;
delete ptr_base;
}
Drukuje:
Typ ptr_base: Base*
Typ pointee :Derived
Testowane z g ++ 4.7.2, g ++ 4.9.0 20140302 (eksperymentalne), clang ++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) w systemie Linux 64-bit oraz g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Jeśli nie możesz korzystać z funkcji C ++ 11, oto jak można to zrobić w C ++ 98, plik type.cpp ma teraz postać :
#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;
handle result( abi::__cxa_demangle(name, NULL, NULL, &status) );
return (status==0) ? result.p : name ;
}
#else
std::string demangle(const char* name) {
return name;
}
#endif
(Aktualizacja z 8 września 2013 r.)
Zaakceptowana odpowiedź (stan na 7 września 2013 r.) , Gdy wywołanie się abi::__cxa_demangle()powiedzie, zwraca wskaźnik do lokalnej tablicy przydzielonej stosowi ... ach!
Zauważ również, że jeśli podasz bufor, abi::__cxa_demangle()zakłada się, że jest on przydzielony na stercie. Przydzielanie bufora na stosie jest błędem (z dokumentacji gnu): "Jeśli output_buffernie jest wystarczająco długi, jest rozszerzany za pomocą realloc." Wywołanie realloc()wskaźnika do stosu ... och! (Zobacz też miły komentarz Igora Skochinsky'ego ).
Możesz łatwo zweryfikować oba te błędy: po prostu zmniejsz rozmiar bufora w akceptowanej odpowiedzi (od 7 września 2013) z 1024 do mniejszego, na przykład 16 i nadaj mu coś o nazwie nie dłuższej niż 15 (tak realloc()jest nie wezwany). Mimo to, w zależności od systemu i optymalizacji kompilatora, wynikiem będzie: śmieci / nic / awaria programu.
Aby zweryfikować drugi błąd: ustaw rozmiar bufora na 1 i wywołaj go czymś, którego nazwa jest dłuższa niż 1 znak. Po uruchomieniu program prawie na pewno ulega awarii, gdy próbuje wywołać realloc()wskaźnik do stosu.
(Stara odpowiedź z 27 grudnia 2010)
Ważne zmiany wprowadzone w kodzie KeithB : bufor musi być przydzielony przez malloc lub określony jako NULL. NIE umieszczaj go na stosie.
Dobrze jest również sprawdzić ten status.
Nie udało mi się znaleźć HAVE_CXA_DEMANGLE. Sprawdzam __GNUG__chociaż to nie gwarantuje, że kod się skompiluje. Czy ktoś ma lepszy pomysł?
#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>. W przeciwnym razie działało świetnie, dzięki.