Учитывая внимание, которое уделяется этому вопросу / ответу, и ценные отзывы от GManNickG , я немного очистил код. Даны две версии: одна с функциями C ++ 11, а другая - только с функциями C ++ 98.
В файле 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
В файле type.cpp (требуется 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
Применение:
#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;
}
Он печатает:
Тип ptr_base: Base*
Тип указателя:Derived
Протестировано с g ++ 4.7.2, g ++ 4.9.0 20140302 (экспериментально), clang ++ 3.4 (магистраль 184647), clang 3.5 (магистраль 202594) на 64-битной Linux и g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Если вы не можете использовать функции C ++ 11, вот как это можно сделать в C ++ 98, теперь файл type.cpp имеет вид:
#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
(Обновление от 8 сентября 2013 г.)
Принятый ответ (по состоянию на 7 сентября 2013 г.) , когда вызов abi::__cxa_demangle()
успешен, возвращает указатель на локальный массив, выделенный стеком ... ой!
Также обратите внимание, что если вы предоставляете буфер, abi::__cxa_demangle()
предполагается , что он размещен в куче. Выделение буфера в стеке является ошибкой (из документации GNU): «Если output_buffer
недостаточно, он расширяется с помощью realloc
.» Вызов realloc()
указателя на стек ... ой! (См. Также добрый комментарий Игоря Скочинского .)
Вы можете легко проверить обе эти ошибки: просто уменьшите размер буфера в принятом ответе (по состоянию на 7 сентября 2013 г.) с 1024 до меньшего, например 16, и дайте ему что-нибудь с именем не длиннее 15 (так realloc()
же не называется). Тем не менее, в зависимости от вашей системы и оптимизации компилятора, вывод будет: мусор / ничего / сбой программы.
Чтобы проверить вторую ошибку: установите размер буфера равным 1 и вызовите его с чем-то, имя которого длиннее 1 символа. Когда вы его запускаете, программа почти наверняка вылетает при попытке вызова realloc()
с указателем на стек.
(Старый ответ от 27 декабря 2010 г.)
Важные изменения, внесенные в код KeithB : буфер должен быть либо выделен malloc, либо указан как NULL. НЕ размещайте его в стеке.
Целесообразно также проверить этот статус.
Найти не удалось HAVE_CXA_DEMANGLE
. Я проверяю, __GNUG__
хотя это не гарантирует, что код даже скомпилируется. У кого-нибудь есть идея получше?
#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>
. В противном случае отлично работало, спасибо.