Frage

Im Moment arbeite ich auf einig Logging-Code, der sollte - unter anderem - Druckinformationen über die aufrufende Funktion. Dies sollte relativ einfach, Standard C ++ eine type_info Klasse. Diese enthält den Namen der typeid'd Klasse / Funktion / etc. aber es ist verstümmelt. Es ist nicht sehr nützlich. D. h typeid(std::vector<int>).name() kehrt St6vectorIiSaIiEE.

Gibt es eine Möglichkeit, etwas Nützliches daraus zu produzieren? Wie std::vector<int> für das obige Beispiel. Wenn es funktioniert nur für Nicht-Template-Klassen, das ist auch in Ordnung.

Die Lösung sollte für gcc arbeiten, aber es wäre besser, wenn ich könnte portieren. Es ist für die Anmeldung so ist es nicht so wichtig, dass sie nicht ausgeschaltet werden können, aber es sollte für das Debuggen hilfreich sein.

War es hilfreich?

Lösung

die Aufmerksamkeit diese Frage / Antwort erhält, und das wertvolle Feedback von GManNickG , ich habe den Code ein wenig aufgeräumt. Zwei Versionen sind gegeben:. Ein mit C ++ 11-Funktionen und ein anderes mit nur C ++ 98-Features

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

Verbrauch:

#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 ptr_base: Base*
Typ pointee: Derived

Getestet mit g ++ 4.7.2, g ++ 4.9.0 20.140.302 (experimentell), Klirren ++ 3.4 (Stamm 184647), klirrte 3.5 (Stamm 202594) auf Linux 64 Bit und g ++ 4.7.2 (Mingw32, Win32 XP SP2).

Wenn Sie nicht C ++ 11-Funktionen verwenden, hier ist, wie es in C ++ 98 durchgeführt wird, wird die Datei type.cpp ist nun:

#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) , wenn der Anruf zu abi::__cxa_demangle() erfolgreich ist, gibt einen Zeiger auf einem lokalen, zugeordnete Array-Stack ... autsch!
Beachten Sie auch, dass, wenn Sie einen Puffer zur Verfügung stellen, abi::__cxa_demangle() nimmt sie auf dem Heap zugewiesen werden. Zuordnen der Puffer auf dem Stack ist ein Fehler (von der Gnu doc): „Wenn output_buffer nicht lang genug ist, wird es erweitert realloc verwendet wird.“ aufrufen realloc() auf einen Zeiger auf den Stapel ... autsch! (Siehe auch Igor Skochinsky 's Art Kommentar.)

Sie können ganz einfach diese beiden Fehler überprüfen: nur die Puffergröße in der akzeptierten Antwort reduzieren (ab 7, September 2013) von 1024 bis etwas kleiner, zum Beispiel 16, und geben Sie ihm etwas mit einem Namen nicht länger als 15 (so realloc() ist nicht genannt). Dennoch je nach System und den Compiler-Optimierungen, wird der Ausgang sein: Müll / nichts / Programmabsturz
. Um den zweiten Fehler zu überprüfen: Stellen Sie die Puffergröße auf 1 und rufen Sie es mit etwas, dessen Name länger als 1 Zeichen. Wenn Sie es ausführen, fast das Programm sicher stürzt wie es realloc() mit einem Zeiger auf den Stapel zu nennen versucht.


(Die alte Antwort vom 27. Dezember 2010)

Wichtige Änderungen an KeithB Code : der Puffer entweder werden durch malloc oder angegeben als NULL zugewiesen . sie es nicht auf dem Stapel zugeordnet werden.

Es ist klug, diesen Status auch zu überprüfen.

ich nicht HAVE_CXA_DEMANGLE zu finden. Ich überprüfe __GNUG__ obwohl das nicht garantiert, dass der Code selbst kompilieren. Jeder hat 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;
}

Andere Tipps

Boost-Kern enthält einen demangler. Kasse Kern / 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>
}

Es ist im Grunde nur ein Wrapper für abi::__cxa_demangle, wie zuvor vorgeschlagen.

Dies ist, was wir verwenden. HAVE_CXA_DEMANGLE wird nur gesetzt, wenn verfügbar (neuere Versionen von GCC nur).

#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  

Hier finden Sie aktuelle type_strings.hpp es enthält eine Funktion, die das tut, was Sie wollen.

Wenn Sie ein Demangling Werkzeug anschauen, die Sie zum Beispiel könnte verwenden Sachen in einer Protokolldatei angezeigt mangle, einen Blick auf c++filt nehmen, die mit binutils kommt. Es kann demangle C ++ und Java Symbolnamen.

Nicht eine komplette Lösung, aber Sie können auf das, was einige der Norm (oder weitgehend unterstützt) Makros definieren zu suchen. Es ist in Logging-Code gemeinsam die Verwendung der Makros finden Sie unter:

__FUNCTION__
__FILE__
__LINE__

e.g.:

log(__FILE__, __LINE__, __FUNCTION__, mymessage);

Es ist Implementierung definiert, so ist es nicht etwas, das tragbar sein wird. In MSVC ++, Name () ist der Name nicht ergänzt, und Sie haben bei RAW_NAME suchen (), um die dekorierte eines zu bekommen.
Nur ein Stich in der Dunkelheit hier, aber unter gcc, können Sie unter aussehen wollen demangle.h

Ich fand auch ein Makro namens __PRETTY_FUNCTION__, die den Trick. Es gibt einen hübschen Funktionsnamen (Zahlen :)). Dies ist, was ich brauchte.

d. es gibt mir die folgende:

virtual bool mutex::do_unlock()

Aber ich glaube nicht, es auf anderen Compilern funktioniert.

Eine leichte Abwandlung Alis Lösung. Wenn Sie den Code immer noch wollen, sehr ähnlich sein

typeid(bla).name(),

Schreiben Sie stattdessen

Typeid(bla).name() (die sich nur in der Hauptstadt Anfangsbuchstaben)

dann können Sie daran interessiert sein:

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());
}
*/

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 bleibt gleich wie in Alis Lösung

Werfen Sie einen Blick auf __cxa_demangle, die Sie bei cxxabi.h finden.

// 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;
  }

Die akzeptierte Lösung [1] meist gut funktioniert. Ich fand mindestens einen Fall (und ich würde es nicht eine Ecke Fall nennen), wo es nicht berichten, was ich erwartet habe ... mit Referenzen.

Für die Fälle, fand ich eine andere Lösung, an der Unterseite geschrieben.

Problematische Fall (mit type wie in [1]):

int i = 1;
cout << "Type of " << "i" << " is " << type(i) << endl;
int & ri = i;
cout << "Type of " << "ri" << " is " << type(ri) << endl;

erzeugt

Type of i is int
Type of ri is int

Lösung (mit type_name<decltype(obj)>(), siehe Code unten):

cout << "Type of " << "i" << " is " << type_name<decltype(i)>() << endl;
cout << "Type of " << "ri" << " is " << type_name<decltype(ri)>() << endl;

erzeugt

Type of i is int
Type of ri is int&

wie gewünscht (zumindest von mir)

Code . Es hat in einem inkludierten Header sein, nicht in einer separat kompilierte Quelle, aufgrund Spezialisierung Fragen. Siehe undefined reference to Template-Funktion zum Beispiel.

#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;
}

Ich wollte schon immer verwenden type_info, aber ich bin sicher, dass das Ergebnis der Namen () Member-Funktion ist Nicht-Standard und wird nicht unbedingt etwas zurückgeben, die zu einem sinnvollen Ergebnis umgewandelt werden können.
Wenn Sie einen Compiler kleben, dort möglicherweise ein Compiler spezifische Funktion, die das tun, was Sie wollen. Überprüfen Sie die Dokumentation.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top