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
Ответы:
Перечисления в C - это числа, которым присвоены удобные имена внутри вашего кода. Они не являются строками, и имена, присвоенные им в исходном коде, не компилируются в вашу программу, поэтому они недоступны во время выполнения.
Единственный способ получить то, что вы хотите, - это написать самостоятельно функцию, которая переводит значение перечисления в строку. Например (при условии, что вы перемещаете объявление за
enum Days
пределы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));
В качестве альтернативы вы можете использовать массив в качестве карты, например
const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ }; /* ... */ printf("%s", dayNames[TheDay]);
Но здесь вы, вероятно, захотите назначить
Sunday = 0
в перечислении, чтобы быть в безопасности ... Я не уверен, что стандарт C требует, чтобы компиляторы начинали перечисление с 0, хотя большинство из них (я уверен, что кто-то прокомментирует, чтобы подтвердить или опровергнуть это ).источник
const char* dayNames[] = {[Sunday] = "Sunday", [Monday] = "Monday", [Tuesday] = "Tuesday", /* ... etc ... */ };
. Вы знаете, на случай, если дни недели переставят, или вы решите, что понедельник будет первым днем недели.Days TheDay = Monday; printf("%s", #TheDay);
напечатает "день".Я использую что-то вроде этого:
в файле "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
затем в любом файле заголовка вы делаете объявление 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)
затем в файле EnumToString.c:
#include "enum.h" #define GENERATE_ENUM_STRINGS // Start string generation #include "enum.h" #undef GENERATE_ENUM_STRINGS // Stop string generation
затем в 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; }
это будет "автоматически" генерировать строки для любых перечислений, объявленных таким образом и включенных в "EnumToString.c"
источник
return _(#element)
и тому подобное.Обычно я это делаю, сохраняя строковые представления в отдельном массиве в том же порядке, а затем индексируя массив с помощью значения перечисления:
const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ }; printf("%s", DayNames[Sunday]); // prints "Sunday"
источник
enum
s в C не работают так, как вы от них ожидаете. Вы можете думать о них как о прославленных константах (с некоторыми дополнительными преимуществами, связанными с тем, что они являются набором таких констант), и текст, который вы написали для "Sunday", действительно преобразуется в число во время компиляции, текст является в конечном итоге отброшен.Вкратце: чтобы делать то, что вы действительно хотите, вам нужно будет сохранить массив строк или создать функцию для сопоставления значения перечисления с текстом, который вы хотите напечатать.
источник
Перечисления в C - это в основном синтаксический сахар для именованных списков автоматически упорядоченных целочисленных значений. То есть, когда у вас есть этот код:
int main() { enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday}; Days TheDay = Monday; }
Ваш компилятор действительно выплевывает это:
int main() { int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0. }
Следовательно, вывод перечисления C в виде строки не является операцией, которая имеет смысл для компилятора. Если вы хотите, чтобы для них были удобочитаемые строки, вам нужно будет определить функции для преобразования из перечислений в строки.
источник
Вот более простой способ сделать это с помощью макросов:
#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; }
Не уверен, что это полностью переносимые ч / б препроцессоры, но он работает с gcc.
Это c99 btw, поэтому используйте,
c99 strict
если вы подключите его к (онлайн-компилятору) ideone .источник
Я знаю, что опаздываю на вечеринку, но как насчет этого?
const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ }; printf("%s", dayNames[Sunday]); // prints "Sunday"
Таким образом, вам не нужно вручную синхронизировать массив
enum
иchar*
массив. Если вы похожи на меня, скорее всего, вы позже изменитеenum
, иchar*
массив будет печатать недопустимые строки. Эта функция может не поддерживаться повсеместно. Но, черт возьми, большинство современных компиляторов C поддерживают этот назначенный стиль инициализации.Вы можете узнать больше о назначенных инициализаторах здесь .
источник
Вопрос в том, что вы хотите написать имя только один раз.
У меня есть такой идеер:
#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"; }
он использует структуру для вставки перечисления, чтобы принтер в строку мог следовать за каждым определением значения перечисления.
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
Отличие от enum в том, что построитель не может сообщить об ошибке, если числа повторяются. если не нравится писать номер,
__LINE__
можно заменить:#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
источник
Я новичок в этом, но оператор switch определенно будет работать
#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; }
источник
Мне нравится, когда в dayNames есть enum. Чтобы сократить набор текста, мы можем сделать следующее:
#define EP(x) [x] = #x /* ENUM PRINT */ const char* dayNames[] = { EP(Sunday), EP(Monday)};
источник
Есть еще одно решение: создайте свой собственный класс динамического перечисления. Означает, что у вас есть
struct
функция и некоторая функция для создания нового перечисления, в котором элементы хранятся в a,struct
и у каждого элемента есть строка для имени. Вам также понадобится какой-то тип для хранения отдельных элементов, функции для их сравнения и так далее. Вот пример:#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; }
Функции перечисления должны быть в отдельной единице перевода, но я объединил их здесь, чтобы упростить.
Преимущество заключается в том, что это решение является гибким, следует принципу DRY, вы можете хранить информацию вместе с каждым элементом, вы можете создавать новые перечисления во время выполнения и можете добавлять новые элементы во время выполнения. Недостатком является то, что это сложно, требует динамического распределения памяти, не может использоваться в
switch
-case
, требует больше памяти и работает медленнее. Вопрос в том, не следует ли вам использовать язык более высокого уровня в тех случаях, когда вам это нужно.источник
TheDay возвращается к некоторому целочисленному типу. Так:
printf("%s", TheDay);
Пытается разобрать TheDay как строку и либо распечатывает мусор, либо дает сбой.
printf не является типобезопасным и доверяет вам передать ему правильное значение. Чтобы распечатать имя значения, вам нужно создать некоторый метод для сопоставления значения перечисления со строкой - либо таблицу поиска, либо гигантский оператор переключения и т. Д.
источник