Dada a atenção que esta pergunta / resposta recebe e o feedback valioso do GManNickG , limpei um pouco o código. Duas versões são fornecidas: uma com recursos do C ++ 11 e outra com apenas recursos do C ++ 98.
No arquivo 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
No arquivo type.cpp (requer 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;
}
Ele imprime:
Tipo de ptr_base: Base*
Tipo de ponta:Derived
Testado com g ++ 4.7.2, g ++ 4.9.0 20140302 (experimental), clang ++ 3.4 (tronco 184647), clang 3.5 (tronco 202594) em Linux 64 bits e g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Se você não pode usar os recursos do C ++ 11, veja como isso pode ser feito no C ++ 98, o arquivo type.cpp agora é:
#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
(Atualização de 8 de setembro de 2013)
A resposta aceita (em 7 de setembro de 2013) , quando a chamada para abi::__cxa_demangle()
for bem-sucedida, retorna um ponteiro para um array local, com pilha alocada ... ai!
Observe também que se você fornecer um buffer, abi::__cxa_demangle()
assume que ele está alocado no heap. Alocar o buffer na pilha é um bug (do documento gnu): "Se output_buffer
não for longo o suficiente, ele é expandido usando realloc
." Invocando realloc()
um ponteiro para a pilha ... ai! (Veja também o comentário gentil de Igor Skochinsky .)
Você pode verificar facilmente esses dois bugs: basta reduzir o tamanho do buffer na resposta aceita (em 7 de setembro de 2013) de 1024 para algo menor, por exemplo 16, e dar a ele algo com um nome não superior a 15 (então realloc()
é não chamado). Ainda assim, dependendo do seu sistema e das otimizações do compilador, a saída será: lixo / nada / travamento do programa.
Para verificar o segundo bug: defina o tamanho do buffer para 1 e chame-o com algo cujo nome seja maior que 1 caractere. Quando você o executa, o programa quase com certeza trava ao tentar chamar realloc()
com um ponteiro para a pilha.
(A resposta antiga de 27 de dezembro de 2010)
Mudanças importantes feitas no código de KeithB : o buffer deve ser alocado por malloc ou especificado como NULL. NÃO o coloque na pilha.
É aconselhável verificar esse status também.
Eu não consegui encontrar HAVE_CXA_DEMANGLE
. Eu verifico, __GNUG__
embora isso não garanta que o código seja compilado. Alguém tem uma ideia melhor?
#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>
. Caso contrário, funcionou muito bem, obrigado.