92 votes

Démêler le résultat de std :: type_info :: name

Je suis en train de travailler sur un certain code d'enregistrement que prévu - entre autres choses - imprimer les informations à propos de l'appel de la fonction. Cela devrait être relativement facile, standard C++ a un type_info classe. Il contient le nom de la typeid avais de classe/fonction/etc. mais c'est mutilé. Il n'est pas très utile. I. e. typeid(std::vector<int>).name() retours St6vectorIiSaIiEE.

Est-il un moyen de produire quelque chose d'utile? Comme std::vector<int> pour l'exemple ci-dessus. Si elle ne fonctionne que pour les non-classes de modèle, c'est bien trop.

La solution devrait fonctionner pour la gcc, mais il serait mieux si je pouvais port. C'est pour l'enregistrement de sorte qu'il n'est pas si important qu'il ne peut pas être désactivé, mais il devrait être très utile pour le débogage.

112voto

Ali Points 18740

Compte tenu de l'attention portée à cette question / réponse reçoit, et les précieux commentaires de GManNickG, j'ai nettoyé un peu le code. Deux versions: l'une avec C++11 caractéristiques et l'autre avec seulement C++98 caractéristiques.

Dans le fichier de type.php

#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

Dans le fichier type.cpp (nécessite le 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

Utilisation:

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

Il imprime:

Type de ptr_base: Base*
Type de pointee: Derived

Testé avec g++ 4.7.2, g++ 4.9.0 20140302 (expérimental), clang++ 3.4 (tronc 184647), clang 3.5 (tronc 202594) sur Linux 64 bits et g++ 4.7.2 (Mingw32, Win32 XP SP2).

Si vous ne pouvez pas utiliser le C++11 caractéristiques, voici comment on peut le faire en C++98, le fichier type.cpp est maintenant:

#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


(Mise à jour à partir du 8 septembre, 2013)

La accepté de répondre (comme de Sep 7, 2013), lors de l'appel à abi::__cxa_demangle() est un succès, retourne un pointeur vers un local, pile allouée tableau... aïe!
Notez également que si vous fournissez un tampon, abi::__cxa_demangle() suppose qu'il est alloué sur le tas. L'allocation de la mémoire tampon dans la pile est un bug (à partir de la gnu doc): "Si output_buffer n'est pas assez long, elle est étendue à l'aide d' realloc." Appelant realloc() sur un pointeur sur la pile... aïe! (Voir aussi Igor Skochinsky'genre de commentaire.)

Vous pouvez facilement vérifier ces deux bugs: il suffit de réduire la taille de la mémoire tampon dans l'acceptation de la réponse (comme d'Sep 7, 2013) de 1024 à quelque chose de plus petit, par exemple 16, et de lui donner quelque chose avec un nom pas plus que 15 (si realloc() est pas appelé). Toujours, selon votre système et les optimisations du compilateur, la sortie sera: déchets / rien / plantage du programme.
Pour vérifier la deuxième bug: définir la taille de la mémoire tampon de 1 et de l'appeler avec quelque chose dont le nom est plus long que 1 caractère. Lorsque vous l'exécutez, le programme presque assurément se bloque, comme il tente d'appeler realloc() avec un pointeur sur la pile.


(La vieille réponse du 27 Décembre 2010)

Modifications importantes apportées à KeithB du code: le tampon doit être allouée par malloc ou NULL. Ne PAS allouer sur la pile.

Il est sage de vérifier le statut.

Je n'ai pas réussi à trouver de l' HAVE_CXA_DEMANGLE. Je vérifie __GNUG__ bien que cela ne garantit pas que le code même de la compilation. Quelqu'un a une meilleure idée?

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

13voto

KeithB Points 9459

C'est ce que nous utilisons. HAVE_CXA_DEMANGLE n'est défini que s'il est disponible (versions récentes de GCC uniquement).

 #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
 

8voto

Ici, jetez un oeil à type_strings.cpp, il contient une fonction qui fait ce que vous voulez.

Si vous recherchez simplement un outil de démêlage, que vous pourriez par exemple utiliser pour modifier les éléments affichés dans un fichier journal, consultez c++filt , qui vient avec binutils. Il peut démêler les noms de symboles C ++ et Java.

4voto

luke Points 16255

Ce n'est pas une solution complète, mais vous voudrez peut-être examiner ce que définissent certaines des macros standard (ou largement prises en charge). Il est courant dans le code de journalisation de voir l'utilisation des macros:

 __FUNCTION__
__FILE__
__LINE__

e.g.:

log(__FILE__, __LINE__, __FUNCTION__, mymessage);
 

4voto

Eclipse Points 27662

C'est la mise en œuvre définie, donc ce n'est pas quelque chose qui va être portable. Dans MSVC ++, name () est le nom non décoré et vous devez consulter raw_name () pour obtenir le décoré.
Juste un coup de couteau dans le noir ici, mais sous gcc, vous voudrez peut-être regarder demangle.h

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X