Data l'attenzione che riceve questa domanda / risposta e il prezioso feedback di GManNickG , ho ripulito un po 'il codice. Vengono fornite due versioni: una con funzionalità C ++ 11 e un'altra con solo funzionalità C ++ 98.
Nel 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
Nel file type.cpp (richiede 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
Utilizzo:
#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;
}
Stampa:
Tipo di ptr_base: Base*
Tipo di punta:Derived
Testato con g ++ 4.7.2, g ++ 4.9.0 20140302 (sperimentale), clang ++ 3.4 (trunk 184647), clang 3.5 (trunk 202594) su Linux 64 bit e g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Se non puoi utilizzare le funzionalità di C ++ 11, ecco come farlo in C ++ 98, il file type.cpp è ora:
#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
(Aggiornamento dall'8 settembre 2013)
La risposta accettata (a partire dal 7 settembre 2013) , quando la chiamata a ha abi::__cxa_demangle()
esito positivo, restituisce un puntatore a un array locale allocato nello stack ... ahi!
Notare inoltre che se si fornisce un buffer, si abi::__cxa_demangle()
presume che sia allocato nell'heap. Allocare il buffer sullo stack è un bug (dal documento gnu): "Se output_buffer
non è abbastanza lungo, viene espanso usando realloc
." Chiamare realloc()
un puntatore allo stack ... ahi! (Vedi anche il gentile commento di Igor Skochinsky .)
Puoi facilmente verificare entrambi questi bug: riduci la dimensione del buffer nella risposta accettata (a partire dal 7 settembre 2013) da 1024 a qualcosa di più piccolo, ad esempio 16, e dagli un nome con un nome non più lungo di 15 (così realloc()
è non chiamato). Tuttavia, a seconda del sistema e delle ottimizzazioni del compilatore, l'output sarà: spazzatura / niente / crash del programma.
Per verificare il secondo bug: imposta la dimensione del buffer su 1 e chiamalo con qualcosa il cui nome è più lungo di 1 carattere. Quando lo esegui, il programma quasi sicuramente va in crash mentre tenta di chiamare realloc()
con un puntatore allo stack.
(La vecchia risposta del 27 dicembre 2010)
Importanti modifiche apportate al codice di KeithB : il buffer deve essere allocato da malloc o specificato come NULL. NON allocarlo in pila.
È consigliabile controllare anche quello stato.
Non sono riuscito a trovare HAVE_CXA_DEMANGLE
. Controllo __GNUG__
anche se ciò non garantisce nemmeno che il codice venga compilato. Qualcuno ha un'idea migliore?
#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>
. Altrimenti ha funzionato alla grande, grazie.