Angesichts der Aufmerksamkeit, die diese Frage / Antwort erhält, und des wertvollen Feedbacks von GManNickG habe ich den Code ein wenig aufgeräumt. Es werden zwei Versionen angegeben: eine mit C ++ 11-Funktionen und eine mit nur C ++ 98-Funktionen.
In der Datei 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
In der Datei type.cpp (erfordert 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
Verwendung:
#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;
}
Es druckt:
Typ von ptr_base: Base*
Typ von Pointee:Derived
Getestet mit g ++ 4.7.2, g ++ 4.9.0 20140302 (experimentell), clang ++ 3.4 (Trunk 184647), clang 3.5 (Trunk 202594) unter Linux 64 Bit und g ++ 4.7.2 (Mingw32, Win32 XP SP2).
Wenn Sie nicht C ++ 11 - Funktionen verwenden können, hier ist , wie es in C ++ 98 durchgeführt werden kann, wird die Datei type.cpp ist jetzt:
#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
(Update vom 8. September 2013)
Die akzeptierte Antwort (Stand: 7. September 2013) gibt bei abi::__cxa_demangle()
erfolgreichem Aufruf von einen Zeiger auf ein lokales Array mit Stapelzuweisung zurück ... autsch!
Beachten Sie außerdem, dass bei der Bereitstellung eines Puffers abi::__cxa_demangle()
davon ausgegangen wird, dass dieser auf dem Heap zugewiesen ist. Das Zuweisen des Puffers auf dem Stapel ist ein Fehler (aus dem Gnu-Dokument): "Wenn output_buffer
es nicht lang genug ist, wird es mit erweitert realloc
." Der Aufruf realloc()
auf einen Zeiger auf den Stapel ... autsch! (Siehe auch Igor Skochinskys freundlichen Kommentar.)
Sie können diese beiden Fehler leicht überprüfen: Reduzieren Sie einfach die Puffergröße in der akzeptierten Antwort (Stand: 7. September 2013) von 1024 auf etwas Kleineres, z. B. 16, und geben Sie etwas mit einem Namen an, der nicht länger als 15 ist (so realloc()
ist es auch) nicht genannt). Abhängig von Ihrem System und den Compiler-Optimierungen lautet die Ausgabe jedoch: Garbage / Nothing / Program Crash.
So überprüfen Sie den zweiten Fehler: Setzen Sie die Puffergröße auf 1 und rufen Sie sie mit etwas auf, dessen Name länger als 1 Zeichen ist. Wenn Sie es ausführen, stürzt das Programm fast sicher ab, wenn es versucht, realloc()
mit einem Zeiger auf den Stapel aufzurufen .
(Die alte Antwort vom 27. Dezember 2010)
Wichtige Änderungen am KeithB-Code : Der Puffer muss entweder von malloc zugewiesen oder als NULL angegeben werden. Ordnen Sie es NICHT dem Stapel zu.
Es ist ratsam, auch diesen Status zu überprüfen.
Ich konnte nicht finden HAVE_CXA_DEMANGLE
. Ich überprüfe, __GNUG__
obwohl dies nicht garantiert, dass der Code überhaupt kompiliert wird. Hat jemand eine bessere Idee?
#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>
. Ansonsten hat super geklappt, danke.output_buffer
Ein mit malloc zugewiesener Speicherbereich mit * Längenbytes, in dem der entwirrte Name gespeichert ist. Wenn output_buffer nicht lang genug ist, wird es mit realloc erweitert. output_buffer kann stattdessen NULL sein; In diesem Fall wird der entwirrte Name in einem Speicherbereich abgelegt, der malloc zugewiesen ist.abi::__cxa_demangle
erwartet, dass es auf dem Heap zugewiesen wird . " Vielen Dank, dass Sie das Dokument nachgeschlagen haben!ret_val
während des Baus geworfen wird. Sie können einen Zielfernrohrschutz verwenden, um sich dagegen zu schützen.std::unique_ptr<char, decltype(&std::free)>
als Signatur für Ihren Zeiger zu verwenden.Boost Core enthält einen Demangler. Kasse core / demangle.hpp :
Es ist im Grunde nur ein Wrapper für
abi::__cxa_demangle
, wie bereits vorgeschlagen wurde.quelle
Das verwenden wir. HAVE_CXA_DEMANGLE wird nur festgelegt, wenn verfügbar (nur aktuelle Versionen von GCC).
quelle
#include <cxxabi.h>
.Hier finden Sie aktuelle type_strings.hpp es eine Funktion enthält , das tut , was Sie wollen.
Wenn Sie nur nach einem Entwirrungswerkzeug suchen, mit dem Sie beispielsweise in einer Protokolldatei angezeigte Inhalte entstellen können, schauen Sie sich
c++filt
das mit binutils gelieferte an. Es kann C ++ - und Java-Symbolnamen entwirren.quelle
abi::__cxa_demangle()
und seine Herkunft<cxxabi.h>
ist nicht GCC-spezifisch - sie waren in der fernen Vergangenheit möglicherweise nur GCC-spezifisch , aber zum Zeitpunkt des Schreibens dieses Beitrags<cxxabi.h>
war dies ein fest verwurzelter Ad-hoc-Standard. Während der Code-Link der Antwort DOI war, kann ich dafür bürgen, dass Clang in diesem Fall erstklassigen Support bietet… siehe auch aus derlibcxxabi
Quelle des Clang : der jeweilige deklarierte, implizite, riesige Test: git.io/vRTBo , git.io/vRTBh , git.io/vRTRf - In den Kommentaren des Testcodes wird darauf hingewiesen, dass die Clang-Implementierung im Vergleich zu GCC in der Lage ist, mehr zu entwirren.Die Implementierung ist definiert, daher ist sie nicht portabel. In MSVC ++ ist name () der nicht dekorierte Name, und Sie müssen sich raw_name () ansehen, um den dekorierten zu erhalten.
Nur ein Stich in die Dunkelheit hier, aber unter gcc möchten Sie vielleicht demangle.h anschauen
quelle
Keine vollständige Lösung, aber Sie sollten sich ansehen, was einige der Standardmakros (oder weit verbreitete Makros) definieren. Bei der Protokollierung von Code wird häufig die Verwendung der Makros angezeigt:
quelle
Ich habe auch ein Makro namens gefunden
__PRETTY_FUNCTION__
, das den Trick macht. Es gibt einen hübschen Funktionsnamen (Zahlen :)). Das brauchte ich.Dh es gibt mir folgendes:
Aber ich denke nicht, dass es auf anderen Compilern funktioniert.
quelle
Eine leichte Variation von Alis Lösung. Wenn Sie möchten, dass der Code immer noch sehr ähnlich ist
typeid(bla).name()
,schreibe dies stattdessen
Typeid(bla).name()
(unterscheidet sich nur im Großbuchstaben)dann könnte Sie das interessieren:
In der Datei type.hpp
type.cpp bleibt wie in Alis Lösung
quelle
Schauen Sie sich an,
__cxa_demangle
was Sie unter finden könnencxxabi.h
.quelle
quelle
Die akzeptierte Lösung [1] funktioniert meistens gut. Ich habe mindestens einen Fall gefunden (und ich würde ihn nicht als Eckfall bezeichnen), in dem nicht berichtet wird, was ich erwartet habe ... mit Referenzen.
Für diese Fälle habe ich eine andere Lösung gefunden, die unten angegeben ist.
Problematischer Fall (unter Verwendung
type
wie in [1] definiert):produziert
Lösung (mit
type_name<decltype(obj)>()
, siehe Code unten):produziert
wie gewünscht (zumindest von mir)
Code . Aufgrund von Spezialisierungsproblemen muss es sich in einem enthaltenen Header befinden, nicht in einer separat kompilierten Quelle. Siehe zum Beispiel den undefinierten Verweis auf die Vorlagenfunktion .
quelle
Ich wollte schon immer type_info verwenden, bin mir aber sicher, dass das Ergebnis der Mitgliedsfunktion name () nicht dem Standard entspricht und nicht unbedingt etwas zurückgibt, das in ein aussagekräftiges Ergebnis konvertiert werden kann.
Wenn Sie sich an einen Compiler halten, gibt es möglicherweise eine compilerspezifische Funktion, die das tut, was Sie wollen. Überprüfen Sie die Dokumentation.
quelle
Nach Alis Lösung ist hier die Alternative mit C ++ 11- Vorlagen, die für meine Verwendung am besten funktioniert hat.
Verwendung:
Wird drucken:
quelle