web-dev-qa-db-fra.com

Imprimer le texte au lieu de la valeur de C enum

int main()
{

  enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

  Days TheDay;

  int j = 0;

  printf("Please enter the day of the week (0 to 6)\n");

  scanf("%d",&j);

  TheDay = Days(j);

  //how to PRINT THE VALUES stored in TheDay

  printf("%s",TheDay);  //   isnt working

  return 0;
}
75
avi

Les énumérations en C sont des nombres qui ont des noms commodes dans votre code. Ce ne sont pas des chaînes et les noms qui leur sont attribués dans le code source ne sont pas compilés dans votre programme et ne sont donc pas accessibles au moment de l'exécution.

Le seul moyen d'obtenir ce que vous voulez est d'écrire vous-même une fonction qui traduit la valeur d'énumération en une chaîne. Par exemple. (en supposant que vous déplacez la déclaration de enum Days en dehors de main):

const char* getDayName(enum Days day) 
{
   switch (day) 
   {
      case Sunday: return "Sunday";
      case Monday: return "Monday";
      /* etc... */
   }
}

/* Then, later in main: */
printf("%s", getDayName(TheDay));

Vous pouvez également utiliser un tableau en tant que carte, par exemple.

const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };

/* ... */

printf("%s", dayNames[TheDay]);

Mais ici, vous voudrez probablement assigner Sunday = 0 dans l'énumération pour être sûr ... Je ne suis pas sûr que le standard C demande aux compilateurs de commencer les énumérations à partir de 0, bien que la plupart le fassent (je suis sûr que quelqu'un commentera pour confirmer ou infirmer ce).

83
Tyler McHenry

J'utilise quelque chose comme ça:

dans un fichier "EnumToString.h":

#undef DECL_ENUM_ELEMENT
#undef DECL_ENUM_ELEMENT_VAL
#undef DECL_ENUM_ELEMENT_STR
#undef DECL_ENUM_ELEMENT_VAL_STR
#undef BEGIN_ENUM
#undef END_ENUM

#ifndef GENERATE_ENUM_STRINGS
    #define DECL_ENUM_ELEMENT( element ) element,
    #define DECL_ENUM_ELEMENT_VAL( element, value ) element = value,
    #define DECL_ENUM_ELEMENT_STR( element, descr ) DECL_ENUM_ELEMENT( element )
    #define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_VAL( element, value )
    #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
    #define END_ENUM( ENUM_NAME ) ENUM_NAME; \
            const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
    #define BEGIN_ENUM( ENUM_NAME) const char * GetString##ENUM_NAME( enum tag##ENUM_NAME index ) {\
        switch( index ) { 
    #define DECL_ENUM_ELEMENT( element ) case element: return #element; break;
    #define DECL_ENUM_ELEMENT_VAL( element, value ) DECL_ENUM_ELEMENT( element )
    #define DECL_ENUM_ELEMENT_STR( element, descr ) case element: return descr; break;
    #define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_STR( element, descr )

    #define END_ENUM( ENUM_NAME ) default: return "Unknown value"; } } ;

#endif

puis, dans n'importe quel fichier d'en-tête, vous faites la déclaration enum, day enum.h

#include "EnumToString.h"

BEGIN_ENUM(Days)
{
    DECL_ENUM_ELEMENT(Sunday) //will render "Sunday"
    DECL_ENUM_ELEMENT(Monday) //will render "Monday"
    DECL_ENUM_ELEMENT_STR(Tuesday, "Tuesday string") //will render "Tuesday string"
    DECL_ENUM_ELEMENT(Wednesday) //will render "Wednesday"
    DECL_ENUM_ELEMENT_VAL_STR(Thursday, 500, "Thursday string") // will render "Thursday string" and the enum will have 500 as value
    /* ... and so on */
}
END_ENUM(MyEnum)

puis dans un fichier nommé EnumToString.c:

#include "enum.h"

#define GENERATE_ENUM_STRINGS  // Start string generation

#include "enum.h"             

#undef GENERATE_ENUM_STRINGS   // Stop string generation

puis dans main.c:

int main(int argc, char* argv[])
{
    Days TheDay = Monday;
    printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "1 - Monday"

    TheDay = Thursday;
    printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "500 - Thursday string"

    return 0;
}

cela générera "automatiquement" les chaînes de toutes les énumérations déclarées de cette façon et incluses dans "EnumToString.c"

27
Vargas

La façon dont je le fais habituellement consiste à stocker les représentations de chaîne dans un tableau séparé dans le même ordre, puis à l'indexer avec la valeur enum:

const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"
5
casablanca

enums in C ne fonctionnent pas vraiment comme vous le souhaitiez. Vous pouvez les penser un peu comme des constantes glorifiées (avec quelques avantages supplémentaires liés au fait d'être un collection de telles constantes), et le texte que vous avez écrit pour "Sunday" est vraiment résolu en nombre lors de la compilation , le texte est finalement rejeté.

En bref: pour faire ce que vous voulez vraiment, vous devez conserver un tableau des chaînes ou créer une fonction permettant de mapper la valeur de l'énum sur le texte que vous souhaitez imprimer.

4
Mark Elliot

Les énumérations en C sont essentiellement un sucre syntaxique pour les listes nommées de valeurs entières séquencées automatiquement. C'est-à-dire quand vous avez ce code:

int main()
{
    enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

    Days TheDay = Monday;
}

Votre compilateur crache réellement ceci:

int main()
{
    int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}

Par conséquent, la sortie d'une énumération C en tant que chaîne n'est pas une opération utile pour le compilateur. Si vous souhaitez utiliser des chaînes lisibles par l'homme, vous devez définir des fonctions permettant de convertir les énumérations en chaînes.

4
jdmichal

Voici une façon plus simple de le faire avec des macros:

#include <stdio.h>
#include <stdlib.h>

#define DOW(X, S)                                                         \
    X(Sunday) S X(Monday) S X(Tuesday) S X(Wednesday) S X(Thursday) S X(Friday) S X(Saturday)

#define COMMA ,

/* declare the enum */
#define DOW_ENUM(DOW) DOW
enum dow {
    DOW(DOW_ENUM, COMMA)
};

/* create an array of strings with the enum names... */
#define DOW_ARR(DOW ) [DOW] = #DOW
const char * const dow_str[] = {
    DOW(DOW_ARR, COMMA)
};

/* ...or create a switchy function. */
static const char * dowstr(int i)
{
#define DOW_CASE(D) case D: return #D

    switch(i) {
        DOW(DOW_CASE, ;);
    default: return NULL;
    }
}


int main(void)
{
    for(int i = 0; i < 7; i++)
        printf("[%d] = «%s»\n", i, dow_str[i]);
    printf("\n");
    for(int i = 0; i < 7; i++)
        printf("[%d] = «%s»\n", i, dowstr(i));
    return 0;
}

Je ne suis pas sûr qu'il s'agisse de préprocesseurs n/b totalement portables, mais cela fonctionne avec gcc.

C99 btw, utilisez donc c99 strict si vous le connectez à (le compilateur en ligne) ideone .

4
Tim Schaeffer

Je sais que je suis en retard à la fête, mais qu'en est-il?

const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ };
printf("%s", dayNames[Sunday]); // prints "Sunday"

De cette façon, vous n'avez pas à maintenir manuellement les tableaux enum et char* en synchronisation. Si vous êtes comme moi, il y a des chances que vous changiez plus tard la enum et que le tableau char* imprime des chaînes non valides .Cela peut ne pas être une fonctionnalité universellement prise en charge. Mais autant que je sache, la plupart des compilateurs du jour C supportent ce style initialier.

Vous pouvez en savoir plus sur les initialiseurs désignés ici .

2
fortytwo

La question est que vous voulez écrire le nom juste une fois.
J'ai un ider comme celui-ci:

#define __ENUM(situation,num) \
    int situation = num;        const char * __##situation##_name = #situation;

    const struct {
        __ENUM(get_other_string, -203);//using a __ENUM Mirco make it ease to write, 
        __ENUM(get_negative_to_unsigned, -204);
        __ENUM(overflow,-205);
//The following two line showing the expanding for __ENUM
        int get_no_num = -201;      const char * __get_no_num_name = "get_no_num";
        int get_float_to_int = -202;        const char * get_float_to_int_name = "float_to_int_name";

    }eRevJson;
#undef __ENUM
    struct sIntCharPtr { int value; const char * p_name; };
//This function transform it to string.
    inline const char * enumRevJsonGetString(int num) {
        sIntCharPtr * ptr = (sIntCharPtr *)(&eRevJson);
        for (int i = 0;i < sizeof(eRevJson) / sizeof(sIntCharPtr);i++) {
            if (ptr[i].value == num) {
                return ptr[i].p_name;
            }
        }
        return "bad_enum_value";
    }

il utilise une structure pour insérer enum, de sorte qu'une imprimante à chaîne puisse suivre chaque valeur enum définie.

int main(int argc, char *argv[]) {  
    int enum_test = eRevJson.get_other_string;
    printf("error is %s, number is %d\n", enumRevJsonGetString(enum_test), enum_test);

>error is get_other_string, number is -203

La différence par rapport au générateur est impossible de signaler une erreur si les nombres sont répétés. si vous n'aimez pas écrire un nombre, __LINE__ pourrait le remplacer:

#define ____LINE__ __LINE__
#define __ENUM(situation) \
    int situation = (____LINE__ - __BASELINE -2);       const char * __##situation##_name = #situation;
constexpr int __BASELINE = __LINE__;
constexpr struct {
    __ENUM(Sunday);
    __ENUM(Monday);
    __ENUM(Tuesday);
    __ENUM(Wednesday);
    __ENUM(Thursday);
    __ENUM(Friday);
    __ENUM(Saturday);
}eDays;
#undef __ENUM
inline const char * enumDaysGetString(int num) {
    sIntCharPtr * ptr = (sIntCharPtr *)(&eDays);
    for (int i = 0;i < sizeof(eDays) / sizeof(sIntCharPtr);i++) {
        if (ptr[i].value == num) {
            return ptr[i].p_name;
        }
    }
    return "bad_enum_value";
}
int main(int argc, char *argv[]) {  
    int d = eDays.Wednesday;
    printf("day %s, number is %d\n", enumDaysGetString(d), d);
    d = 1;
    printf("day %s, number is %d\n", enumDaysGetString(d), d);
}

>day Wednesday, number is 3>day Monday, number is 1

1
user8931844

J'aime que cela ait une énumération dans les noms dayNames .

#define EP(x) [x] = #x  /* ENUM PRINT */

const char* dayNames[] = { EP(Sunday), EP(Monday)};
0
Heng lou

je suis nouveau à cela, mais une déclaration de commutateur fonctionnera certainement

#include <stdio.h>

enum mycolor;

int main(int argc, const char * argv[])

{
enum Days{Sunday=1,Monday=2,Tuesday=3,Wednesday=4,Thursday=5,Friday=6,Saturday=7};

enum Days TheDay;


printf("Please enter the day of the week (0 to 6)\n");

scanf("%d",&TheDay);

switch (TheDay)
 {

case Sunday:
        printf("the selected day is sunday");
        break;
    case Monday:
        printf("the selected day is monday");
        break;
    case Tuesday:
        printf("the selected day is Tuesday");
        break;
    case Wednesday:
        printf("the selected day is Wednesday");
        break;
    case Thursday:
        printf("the selected day is thursday");
        break;
    case Friday:
        printf("the selected day is friday");
        break;
    case Saturday:
        printf("the selected day is Saturaday");
        break;
    default:
        break;
}

return 0;
}
0
Suraj K Thomas