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
Respuestas:
Las enumeraciones en C son números que tienen nombres convenientes dentro de su código. No son cadenas y los nombres que se les asignan en el código fuente no se compilan en su programa, por lo que no son accesibles en tiempo de ejecución.
La única forma de obtener lo que desea es escribir usted mismo una función que traduzca el valor de la enumeración en una cadena. Por ejemplo (asumiendo aquí que mueves la declaración de
enum Days
fuera 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, puede usar una matriz como mapa, por ejemplo
const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ }; /* ... */ printf("%s", dayNames[TheDay]);
Pero aquí probablemente desee asignar
Sunday = 0
en la enumeración para estar seguro ... No estoy seguro de si el estándar C requiere que los compiladores comiencen las enumeraciones desde 0, aunque la mayoría lo hace (estoy seguro de que alguien comentará para confirmar o negar esto ).fuente
const char* dayNames[] = {[Sunday] = "Sunday", [Monday] = "Monday", [Tuesday] = "Tuesday", /* ... etc ... */ };
. Ya sabes, en caso de que se reordenen los días de la semana, o decidas que el lunes es el primer día de la semana.Days TheDay = Monday; printf("%s", #TheDay);
imprimiría "TheDay".Yo uso algo como esto:
en un archivo "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
luego, en cualquier archivo de encabezado, realiza la declaración de enumeración, día 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)
luego en un archivo llamado EnumToString.c:
#include "enum.h" #define GENERATE_ENUM_STRINGS // Start string generation #include "enum.h" #undef GENERATE_ENUM_STRINGS // Stop string generation
luego en 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; }
esto generará "automáticamente" las cadenas para cualquier enumeración declarada de esta manera e incluida en "EnumToString.c"
fuente
return _(#element)
y similares.La forma en que normalmente hago esto es almacenando las representaciones de cadenas en una matriz separada en el mismo orden, luego indexando la matriz con el valor de enumeración:
const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ }; printf("%s", DayNames[Sunday]); // prints "Sunday"
fuente
enum
Los s en C no funcionan realmente de la forma esperada. Puede pensar en ellos como constantes glorificadas (con algunos beneficios adicionales relacionados con ser una colección de tales constantes), y el texto que ha escrito para "Domingo" realmente se resuelve en un número durante la compilación, el texto es finalmente descartado.En resumen: para hacer lo que realmente desea, deberá mantener una matriz de las cadenas o crear una función para asignar el valor de la enumeración al texto que desea imprimir.
fuente
Las enumeraciones en C son básicamente azúcar sintáctico para listas nombradas de valores enteros secuenciados automáticamente. Es decir, cuando tienes este código:
int main() { enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday}; Days TheDay = Monday; }
Su compilador en realidad escupe esto:
int main() { int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0. }
Por lo tanto, generar una enumeración de C como una cadena no es una operación que tenga sentido para el compilador. Si desea tener cadenas legibles por humanos para estos, deberá definir funciones para convertir de enumeraciones a cadenas.
fuente
Aquí hay una forma más limpia de hacerlo con 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; }
No estoy seguro de que se trate de preprocesadores b / n totalmente portátiles, pero funciona con gcc.
Esto es c99 por cierto, así
c99 strict
que úselo si lo conecta a ideone (el compilador en línea) .fuente
Sé que llego tarde a la fiesta, pero ¿qué tal esto?
const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ }; printf("%s", dayNames[Sunday]); // prints "Sunday"
De esta manera, no es necesario que mantenga sincronizados manualmente
enum
lachar*
matriz y la matriz. Si es como yo, lo más probable es que luego cambieenum
y lachar*
matriz imprima cadenas no válidas. Es posible que esta característica no sea compatible universalmente. Pero afaik, la mayoría de los compiladores de C del día de hoy apoyan este estilo inicial designado.Puede leer más sobre los inicializadores designados aquí .
fuente
La pregunta es si desea escribir el nombre solo una vez.
Tengo una ider como esta:
#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"; }
usa una estructura para insertar enumeración, de modo que una impresora a cadena pueda seguir cada valor de enumeración definido.
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 diferencia con la enumeración es que el constructor no puede informar de errores si los números se repiten. si no le gusta escribir el número,
__LINE__
podría reemplazarlo:#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
fuente
Soy nuevo en esto, pero una declaración de cambio 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; }
fuente
Me gusta que esto tenga enum en los dayNames. Para reducir la escritura, podemos hacer lo siguiente:
#define EP(x) [x] = #x /* ENUM PRINT */ const char* dayNames[] = { EP(Sunday), EP(Monday)};
fuente
Hay otra solución: cree su propia clase de enumeración dinámica. Significa que tiene una
struct
función y alguna para crear una nueva enumeración, que almacena los elementos en unastruct
y cada elemento tiene una cadena para el nombre. También necesita algún tipo para almacenar elementos individuales, funciones para compararlos, etc. Aquí hay un ejemplo:#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; }
Las funciones de enumeración deben estar en su propia unidad de traducción, pero las combiné aquí para hacerlo más simple.
La ventaja es que esta solución es flexible, sigue el principio DRY, puede almacenar información junto con cada elemento, puede crear nuevas enumeraciones durante el tiempo de ejecución y puede agregar nuevos elementos durante el tiempo de ejecución. La desventaja es que es complejo, necesita una asignación de memoria dinámica, no se puede usar en
switch
-case
, necesita más memoria y es más lento. La pregunta es si no debería utilizar un lenguaje de nivel superior en los casos en que lo necesite.fuente
TheDay se asigna de nuevo a algún tipo de entero. Entonces:
printf("%s", TheDay);
Intenta analizar TheDay como una cadena e imprime basura o se bloquea.
printf no es de tipo seguro y confía en que le pasará el valor correcto. Para imprimir el nombre del valor, necesitaría crear algún método para asignar el valor de enumeración a una cadena, ya sea una tabla de búsqueda, una declaración de cambio gigante, etc.
fuente