Учитывая внимание, которое уделяется этому вопросу / ответу, и ценные отзывы от 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>
. В противном случае отлично работало, спасибо.output_buffer
Область памяти, выделенная с помощью malloc, размером * байтов, в которой хранится разоблаченное имя. Если output_buffer недостаточно длинный, он расширяется с помощью realloc. output_buffer вместо этого может быть NULL; в этом случае разоблаченное имя помещается в область памяти, выделенную с помощью malloc.abi::__cxa_demangle
ожидал, что он будет размещен в куче». Большое спасибо за просмотр документа!ret_val
бросить во время строительства. Вы можете использовать защиту прицела, чтобы защититься от этого.std::unique_ptr<char, decltype(&std::free)>
в качестве подписи для вашего указателя.Ядро Boost содержит деманглер. Оформить заказ core / demangle.hpp :
#include <boost/core/demangle.hpp> #include <typeinfo> #include <iostream> template<class T> struct X { }; int main() { char const * name = typeid( X<int> ).name(); std::cout << name << std::endl; // prints 1XIiE std::cout << boost::core::demangle( name ) << std::endl; // prints X<int> }
По сути, это просто оболочка для
abi::__cxa_demangle
, как предлагалось ранее.источник
Это то, что мы используем. HAVE_CXA_DEMANGLE устанавливается, только если доступно (только в последних версиях GCC).
#ifdef HAVE_CXA_DEMANGLE const char* demangle(const char* name) { char buf[1024]; unsigned int size=1024; int status; char* res = abi::__cxa_demangle (name, buf, &size, &status); return res; } #else const char* demangle(const char* name) { return name; } #endif
источник
#include <cxxabi.h>
.Здесь взгляните на type_strings.hpp, он содержит функцию, которая делает то, что вы хотите.
Если вы просто ищете инструмент для разборки цепочек, который вы, например, могли бы использовать для искажения информации, отображаемой в файле журнала, взгляните на него
c++filt
, который поставляется с binutils. Он может распутывать имена символов C ++ и Java.источник
abi::__cxa_demangle()
и подобные<cxxabi.h>
им не являются специфичными для GCC - они, возможно, были только для GCC в далеком прошлом, но на момент написания этого поста<cxxabi.h>
были укоренившимся специальным стандартом. Итак, хотя ссылка на код ответа была DOI, я могу поручиться за Clang, обеспечивающую первоклассную поддержку в этом случае ... qv, изlibcxxabi
источника Clang : соответствующий decl, impl, огромный тест: git.io/vRTBo , git.io/vRTBh , git.io/vRTRf - комментарии тестового кода отмечают, что реализация Clang способна каким-то образом более детально разбираться, чем GCC.Его реализация определена, так что переносимость не будет. В MSVC ++ name () - это недекорированное имя, и вам нужно посмотреть на raw_name (), чтобы получить декорированное.
Здесь просто удар в темноте, но в gcc вы можете посмотреть demangle.h
источник
Я также нашел макрос с именем
__PRETTY_FUNCTION__
, который делает свое дело. Это дает красивое имя функции (цифры :)). Это то, что мне было нужно.Т.е. это дает мне следующее:
virtual bool mutex::do_unlock()
Но я не думаю, что это работает на других компиляторах.
источник
Это не полное решение, но вы можете посмотреть, что определяют некоторые стандартные (или широко поддерживаемые) макросы. В коде ведения журнала часто можно увидеть использование макросов:
__FUNCTION__ __FILE__ __LINE__ e.g.: log(__FILE__, __LINE__, __FUNCTION__, mymessage);
источник
Небольшая вариация решения Али. Если вы хотите, чтобы код оставался очень похожим на
typeid(bla).name()
,писать это вместо
Typeid(bla).name()
(отличается только первой заглавной буквой)тогда вам может быть интересно это:
В файле 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()); } */ class Typeid { public: template <class T> Typeid(const T& t) : typ(typeid(t)) {} std::string name() { return demangle(typ.name()); } private: const std::type_info& typ; }; #endif
type.cpp остается таким же, как в решении Али
источник
Взгляните на то,
__cxa_demangle
что вы можете найти наcxxabi.h
.источник
// KeithB's solution is good, but has one serious flaw in that unless buf is static // it'll get trashed from the stack before it is returned in res - and will point who-knows-where // Here's that problem fixed, but the code is still non-re-entrant and not thread-safe. // Anyone care to improve it? #include <cxxabi.h> // todo: javadoc this properly const char* demangle(const char* name) { static char buf[1024]; size_t size = sizeof(buf); int status; // todo: char* res = abi::__cxa_demangle (name, buf, &size, &status); buf[sizeof(buf) - 1] = 0; // I'd hope __cxa_demangle does this when the name is huge, but just in case. return res; }
источник
Общепринятое решение [1] работает в основном хорошо. Я нашел по крайней мере один случай (и я бы не назвал его угловым), когда он не сообщает того, чего я ожидал ... со ссылками.
Для этих случаев я нашел другое решение, размещенное внизу.
Проблемный случай (использование,
type
как определено в [1]):int i = 1; cout << "Type of " << "i" << " is " << type(i) << endl; int & ri = i; cout << "Type of " << "ri" << " is " << type(ri) << endl;
производит
Type of i is int Type of ri is int
Решение (использование
type_name<decltype(obj)>()
, см. Код ниже):cout << "Type of " << "i" << " is " << type_name<decltype(i)>() << endl; cout << "Type of " << "ri" << " is " << type_name<decltype(ri)>() << endl;
производит
Type of i is int Type of ri is int&
по желанию (по крайней мере, мной)
Код . Он должен быть во включенном заголовке, а не в отдельно скомпилированном источнике из-за проблем со специализацией. См., Например, неопределенную ссылку на функцию шаблона .
#ifndef _MSC_VER # include <cxxabi.h> #endif #include <memory> #include <string> #include <cstdlib> template <class T> std::string type_name() { typedef typename std::remove_reference<T>::type TR; std::unique_ptr<char, void(*)(void*)> own ( #ifndef _MSC_VER abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr), #else nullptr, #endif std::free ); std::string r = own != nullptr ? own.get() : typeid(TR).name(); if (std::is_const<TR>::value) r += " const"; if (std::is_volatile<TR>::value) r += " volatile"; if (std::is_lvalue_reference<T>::value) r += "&"; else if (std::is_rvalue_reference<T>::value) r += "&&"; return r; }
источник
Я всегда хотел использовать type_info, но уверен, что результат функции-члена name () нестандартен и не обязательно вернет что-либо, что можно преобразовать в значимый результат.
Если вы придерживаетесь одного компилятора, возможно, есть специальная функция компилятора, которая будет делать то, что вы хотите. Проверить документацию.
источник
Следуя решению Али, вот шаблонная альтернатива C ++ 11, которая лучше всего подходит для моего использования.
// type.h #include <cstdlib> #include <memory> #include <cxxabi.h> template <typename T> std::string demangle() { int status = -4; std::unique_ptr<char, void (*)(void*)> res{ abi::__cxa_demangle(typeid(T).name(), NULL, NULL, &status), std::free}; return (status == 0) ? res.get() : typeid(T).name(); }
Применение:
// main.cpp #include <iostream> namespace test { struct SomeStruct {}; } int main() { std::cout << demangle<double>() << std::endl; std::cout << demangle<const int&>() << std::endl; std::cout << demangle<test::SomeStruct>() << std::endl; return 0; }
Напечатаем:
double int test::SomeStruct
источник