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_buffer
nie 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.