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;
}
87
Respostas:
Enumerações em C são números que possuem nomes convenientes dentro de seu código. Eles não são strings e os nomes atribuídos a eles no código-fonte não são compilados em seu programa e, portanto, não são acessíveis em tempo de execução.
A única maneira de obter o que deseja é escrever você mesmo uma função que traduza o valor de enumeração em uma string. Por exemplo (supondo que você mova a declaração de
enum Days
fora demain
):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));
Alternativamente, você pode usar uma matriz como um mapa, por exemplo
const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ }; /* ... */ printf("%s", dayNames[TheDay]);
Mas aqui você provavelmente desejaria atribuir
Sunday = 0
na enumeração para ser seguro ... Não tenho certeza se o padrão C exige que os compiladores comecem as enumerações a partir de 0, embora a maioria faça (tenho certeza que alguém comentará para confirmar ou negar isso )fonte
const char* dayNames[] = {[Sunday] = "Sunday", [Monday] = "Monday", [Tuesday] = "Tuesday", /* ... etc ... */ };
. Você sabe, caso os dias da semana sejam reordenados, ou você decida que segunda-feira é o primeiro dia da semana.Days TheDay = Monday; printf("%s", #TheDay);
imprimiria "O Dia".Eu uso algo assim:
em um arquivo "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
então, em qualquer arquivo de cabeçalho, você faz a declaração 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)
em seguida, em um arquivo chamado EnumToString.c:
#include "enum.h" #define GENERATE_ENUM_STRINGS // Start string generation #include "enum.h" #undef GENERATE_ENUM_STRINGS // Stop string generation
então em 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; }
isto irá gerar "automaticamente" as strings para quaisquer enums declarados desta forma e incluídos em "EnumToString.c"
fonte
return _(#element)
e semelhantes.Normalmente, faço isso armazenando as representações de string em uma matriz separada na mesma ordem e, em seguida, indexando a matriz com o valor enum:
const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ }; printf("%s", DayNames[Sunday]); // prints "Sunday"
fonte
enum
s em C realmente não funcionam da maneira que você espera que funcionem. Você pode pensar nelas como constantes glorificadas (com alguns benefícios adicionais relacionados a ser uma coleção de tais constantes), e o texto que você escreveu para "Domingo" realmente é resolvido em um número durante a compilação, o texto é finalmente descartados.Resumindo: para fazer o que você realmente deseja, você precisará manter um array de strings ou criar uma função para mapear do valor do enum para o texto que deseja imprimir.
fonte
Enumerações em C são basicamente açúcar sintático para listas nomeadas de valores inteiros sequenciados automaticamente. Ou seja, quando você tiver este código:
int main() { enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday}; Days TheDay = Monday; }
Seu compilador realmente expõe isto:
int main() { int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0. }
Portanto, a saída de uma enumeração C como uma string não é uma operação que faz sentido para o compilador. Se você quiser ter strings legíveis por humanos para eles, precisará definir funções para converter de enumerações em strings.
fonte
Esta é uma maneira mais limpa de fazer isso com 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; }
Não tenho certeza se este é um pré-processador p / b totalmente portátil, mas funciona com gcc.
Este é c99 btw, então use
c99 strict
se você conectá-lo (o compilador online) ideone .fonte
Eu sei que estou atrasado para a festa, mas que tal isso?
const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ }; printf("%s", dayNames[Sunday]); // prints "Sunday"
Dessa forma, você não precisa manter manualmente o
enum
e ochar*
array em sincronia. Se você for como eu, é provável que mais tarde altere oenum
e ochar*
array imprima strings inválidas. Este pode não ser um recurso com suporte universal. Mas afaik, a maioria dos compiladores C mais modernos suportam este estilo inicial designado.Você pode ler mais sobre inicializadores designados aqui .
fonte
A questão é que você deseja escrever o nome apenas uma vez.
Eu tenho um ider assim:
#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"; }
ele usa uma estrutura para inserir enum, de forma que uma impressora para string possa seguir cada definição de valor de enum.
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
A diferença para enum é que o construtor não pode relatar erros se os números forem repetidos. se você não gosta de escrever o número,
__LINE__
pode substituí-lo:#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
fonte
eu sou novo nisso, mas uma instrução switch definitivamente funcionará
#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; }
fonte
Gosto que tenha enum nos dayNames. Para reduzir a digitação, podemos fazer o seguinte:
#define EP(x) [x] = #x /* ENUM PRINT */ const char* dayNames[] = { EP(Sunday), EP(Monday)};
fonte
Existe outra solução: Crie sua própria classe de enumeração dinâmica. Significa que você tem uma
struct
função e alguma para criar uma nova enumeração, que armazena os elementos em astruct
e cada elemento tem uma string para o nome. Você também precisa de algum tipo para armazenar elementos individuais, funções para compará-los e assim por diante. Aqui está um exemplo:#include <stdarg.h> #include <stdbool.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct Enumeration_element_T { size_t index; struct Enumeration_T *parrent; char *name; }; struct Enumeration_T { size_t len; struct Enumeration_element_T elements[]; }; void enumeration_delete(struct Enumeration_T *self) { if(self) { while(self->len--) { free(self->elements[self->len].name); } free(self); } } struct Enumeration_T *enumeration_create(size_t len,...) { //We do not check for size_t overflows, but we should. struct Enumeration_T *self=malloc(sizeof(self)+sizeof(self->elements[0])*len); if(!self) { return NULL; } self->len=0; va_list l; va_start(l,len); for(size_t i=0;i<len;i++) { const char *name=va_arg(l,const char *); self->elements[i].name=malloc(strlen(name)+1); if(!self->elements[i].name) { enumeration_delete(self); return NULL; } strcpy(self->elements[i].name,name); self->len++; } return self; } bool enumeration_isEqual(struct Enumeration_element_T *a,struct Enumeration_element_T *b) { return a->parrent==b->parrent && a->index==b->index; } bool enumeration_isName(struct Enumeration_element_T *a, const char *name) { return !strcmp(a->name,name); } const char *enumeration_getName(struct Enumeration_element_T *a) { return a->name; } struct Enumeration_element_T *enumeration_getFromName(struct Enumeration_T *self, const char *name) { for(size_t i=0;i<self->len;i++) { if(enumeration_isName(&self->elements[i],name)) { return &self->elements[i]; } } return NULL; } struct Enumeration_element_T *enumeration_get(struct Enumeration_T *self, size_t index) { return &self->elements[index]; } size_t enumeration_getCount(struct Enumeration_T *self) { return self->len; } bool enumeration_isInRange(struct Enumeration_T *self, size_t index) { return index<self->len; } int main(void) { struct Enumeration_T *weekdays=enumeration_create(7,"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"); if(!weekdays) { return 1; } printf("Please enter the day of the week (0 to 6)\n"); size_t j = 0; if(scanf("%zu",&j)!=1) { enumeration_delete(weekdays); return 1; } // j=j%enumeration_getCount(weekdays); //alternative way to make sure j is in range if(!enumeration_isInRange(weekdays,j)) { enumeration_delete(weekdays); return 1; } struct Enumeration_element_T *day=enumeration_get(weekdays,j); printf("%s\n",enumeration_getName(day)); enumeration_delete(weekdays); return 0; }
As funções de enumeração devem estar em sua própria unidade de tradução, mas eu as combinei aqui para torná-la mais simples.
A vantagem é que esta solução é flexível, segue o princípio DRY, você pode armazenar informações junto com cada elemento, pode criar novas enumerações durante o tempo de execução e pode adicionar novos elementos durante o tempo de execução. A desvantagem é que isso é complexo, precisa de alocação dinâmica de memória, não pode ser usado em
switch
-case
, precisa de mais memória e é mais lento. A questão é se você não deve usar uma linguagem de nível superior nos casos em que for necessário.fonte
TheDay mapeia de volta para algum tipo inteiro. Então:
printf("%s", TheDay);
Tenta analisar TheDay como uma string e irá imprimir lixo ou travar.
printf não é typesafe e confia em você para passar o valor correto para ele. Para imprimir o nome do valor, você precisa criar algum método para mapear o valor enum para uma string - uma tabela de pesquisa, uma instrução switch gigante etc.
fonte