Печатать текст вместо значения из C enum - PullRequest
75 голосов
/ 02 июля 2010
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;
}

Ответы [ 10 ]

86 голосов
/ 02 июля 2010

Перечисления в 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, хотя большинство так и делает (уверен, кто-то комментарий, чтобы подтвердить или опровергнуть это).

27 голосов
/ 02 июля 2010

Я использую что-то вроде этого:

в файле "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

5 голосов
/ 02 июля 2010

Обычно я делаю это, сохраняя строковые представления в отдельном массиве в том же порядке, а затем индексируя массив со значением перечисления:

const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"
4 голосов
/ 03 июля 2010

Вот более чистый способ сделать это с помощью макросов:

#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, кстати, поэтому используйте c99 strict, если подключите его к (онлайн-компилятору) ideone .

4 голосов
/ 02 июля 2010

Перечисления в 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 в виде строки не является операцией, которая имеет смыслкомпилятору.Если вы хотите иметь для них удобочитаемые строки, вам необходимо определить функции для преобразования из перечислений в строки.

4 голосов
/ 02 июля 2010

enum с в С на самом деле не работают так, как вы ожидаете.Вы можете думать о них как о прославленных константах (с некоторыми дополнительными преимуществами, связанными с коллекцией таких констант), и текст, который вы написали для "Sunday", действительно разрешается в числово время компиляции текст в конечном итоге отбрасывается.

Короче говоря: чтобы делать то, что вам действительно нужно, вам нужно сохранить массив строк или создать функцию для сопоставления значения enum с текстом, который вы 'Я хотел бы напечатать.

2 голосов
/ 29 января 2016

Я знаю, что опаздываю на вечеринку, но как насчет этого?

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

Таким образом, вам не нужно вручную синхронизировать массивы enum и char*. Если вы похожи на меня, скорее всего, вы позже измените enum, а массив char* выведет недопустимые строки. Это не может быть универсально поддерживаемой функцией. Но, на самом деле, большинство современных компиляторов C поддерживают этот назначенный начальный стиль.

Подробнее о назначенных инициализаторах можно прочитать здесь .

0 голосов
/ 11 марта 2017

Мне нравится иметь enum в dayNames. Чтобы уменьшить объем печати, мы можем сделать следующее:

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

const char* dayNames[] = { EP(Sunday), EP(Monday)};
0 голосов
/ 09 марта 2015

Я новичок в этом, но оператор 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;
}
0 голосов
/ 02 июля 2010

TheDay отображается обратно в некоторый целочисленный тип.Итак:

printf("%s", TheDay);

Пытается проанализировать TheDay как строку и распечатает мусор или произойдет сбой.

printf не безопасен и доверяет вам передать ему правильное значение.Чтобы распечатать имя значения, вам нужно создать какой-то метод для отображения значения перечисления в строку - либо таблицу поиска, оператор гигантского переключателя и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...