158 votes

Comment convertir une variable de type enum en chaîne?

Comment faire printf pour montrer les valeurs des variables qui sont de type enum? Par exemple:

 typedef enum {Linux, Apple, Windows} OS_type; 
OS_type myOS = Linux;
 

et ce dont j'ai besoin, c'est qch comme

 printenum(OS_type, "My OS is %s", myOS);
 

qui doit montrer une chaîne "Linux", pas un entier.

Je suppose que je dois d’abord créer un tableau de chaînes indexé en fonction de la valeur. Mais je ne sais pas quelle est la plus belle façon de le faire. Est-ce possible?

143voto

James McNellis Points 193607

La solution naïve, bien sûr, est d'écrire une fonction pour chaque énumération qui effectue la conversion en chaîne de caractères:

enum OS_type { Linux, Apple, Windows };

inline const char* ToString(OS_type v)
{
    switch (v)
    {
        case Linux:   return "Linux";
        case Apple:   return "Apple";
        case Windows: return "Windows";
        default:      return "[Unknown OS_type]";
    }
}

Ceci, cependant, est un entretien de catastrophe. Avec l'aide de la poussée.Préprocesseur de la bibliothèque, qui peut être utilisé à la fois avec code C et C++, vous pouvez facilement profiter de la préprocesseur et laisser générer cette fonction pour vous. La génération de macro est comme suit:

#include <boost/preprocessor.hpp>

#define X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE(r, data, elem)    \
    case elem : return BOOST_PP_STRINGIZE(elem);

#define DEFINE_ENUM_WITH_STRING_CONVERSIONS(name, enumerators)                \
    enum name {                                                               \
        BOOST_PP_SEQ_ENUM(enumerators)                                        \
    };                                                                        \
                                                                              \
    inline const char* ToString(name v)                                       \
    {                                                                         \
        switch (v)                                                            \
        {                                                                     \
            BOOST_PP_SEQ_FOR_EACH(                                            \
                X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE,          \
                name,                                                         \
                enumerators                                                   \
            )                                                                 \
            default: return "[Unknown " BOOST_PP_STRINGIZE(name) "]";         \
        }                                                                     \
    }

La première macro (en commençant par X_) est utilisée en interne par le second. La deuxième macro génère d'abord l'énumération, puis génère un ToString fonction qui prend un objet de ce type et retourne le nom de l'agent recenseur comme une chaîne de caractères (cette mise en œuvre, pour des raisons évidentes, exige que les agents recenseurs de la carte pour les valeurs uniques).

En C++, vous pourriez mettre en œuvre l' ToString fonction operator<< de surcharge à la place, mais je pense que c'est un peu plus propre pour exiger un explicite "ToString" pour convertir la valeur en la forme d'une chaîne.

Comme exemple d'utilisation, votre OS_type énumération serait définie comme suit:

DEFINE_ENUM_WITH_STRING_CONVERSIONS(OS_type, (Linux)(Apple)(Windows))

Alors que la macro apparaît à première vue comme c'est beaucoup de travail, et la définition de l' OS_type semble assez étrangère, n'oubliez pas que vous avez à écrire la macro une fois, alors vous pouvez l'utiliser pour chaque énumération. Vous pouvez ajouter des fonctionnalités supplémentaires (par exemple, une chaîne formulaire enum conversion) sans trop de difficulté, et il résout complètement le problème de l'entretien, puisque vous n'avez qu'à fournir les noms une fois, lors de l'appel de la macro.

L'énumération peut ensuite être utilisé comme si c'était définie normalement:

#include <iostream>

int main()
{
    OS_type t = Windows;
    std::cout << ToString(t) << " " << ToString(Apple) << std::endl;
}

Les extraits de code dans ce post, en commençant par l' #include <boost/preprocessor.hpp> de la ligne, peut être compilé comme affiché à démontrer la solution.

Cette solution est pour le C++ car il utilise C++, la syntaxe spécifique (par exemple, pas de typedef enum) et de surcharge de fonctions, mais il serait très simple pour faire ce travail avec C ainsi.

81voto

Bo Persson Points 42821

Il n'y a vraiment pas de belle façon de faire cela. Configurez simplement un tableau de chaînes indexées par l'énum.

Si vous effectuez beaucoup de sorties, vous pouvez définir un opérateur << qui prend un paramètre enum et effectue la recherche pour vous.

36voto

Reno Points 22138

C'est le bloc de préprocesseur

 #ifndef GENERATE_ENUM_STRINGS
    #define DECL_ENUM_ELEMENT( element ) element
    #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
    #define END_ENUM( ENUM_NAME ) ENUM_NAME; \
            char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
    #define DECL_ENUM_ELEMENT( element ) #element
    #define BEGIN_ENUM( ENUM_NAME ) char* gs_##ENUM_NAME [] =
    #define END_ENUM( ENUM_NAME ) ; char* GetString##ENUM_NAME(enum \
            tag##ENUM_NAME index){ return gs_##ENUM_NAME [index]; }
#endif
 

Définition Enum

 BEGIN_ENUM(Os_type)
{
    DECL_ENUM_ELEMENT(winblows),
    DECL_ENUM_ELEMENT(hackintosh),
}
 

Appeler en utilisant

 GetStringOs_type(winblows);
 

Pris d' ici . À quel point cela est cool ? :)

8voto

Nawaz Points 148870

Utilisez std::map<OS_type, std::string> et remplissez-le avec enum en tant que clé et représentation sous forme de chaîne en tant que valeurs. Vous pouvez alors procéder comme suit:

 printf("My OS is %s", enumMap[myOS]);
std::cout << enumMap[myOS] ;
 

7voto

Andrew Points 403

Le problème avec C enums est que ce n'est pas un type en soi, comme c'est le cas en C ++. Une énumération en C est un moyen de mapper des identificateurs à des valeurs intégrales. Juste ça. C'est pourquoi une valeur enum est interchangeable avec des valeurs entières.

Comme vous vous en doutez, un bon moyen consiste à créer un mappage entre la valeur enum et une chaîne. Par exemple:

 char * OS_type_label[] = {
    "Linux",
    "Apple",
    "Windows"
};
 

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