Program Tip

C enum의 값 대신 텍스트 인쇄

programtip 2020. 10. 14. 20:53
반응형

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;
}

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부터 열거 형을 시작하도록 요구하는지 확실하지 않습니다. 대부분의 경우에도 그렇습니다. ).


다음과 같이 사용합니다.

"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"에 포함 된 열거 형에 대한 문자열이 "자동으로"생성됩니다.


일반적으로 이렇게하는 방법은 문자열 표현을 같은 순서로 별도의 배열에 저장 한 다음 열거 형 값으로 배열을 인덱싱하는 것입니다.

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

enumC의 s는 예상대로 작동하지 않습니다. 당신은 그것들을 영광스러운 상수와 비슷하다고 생각할 수 있습니다. ( 이러한 상수 모음 과 관련된 몇 가지 추가적인 이점이 있습니다. ) "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이므로 (온라인 컴파일러) ideone에c99 strict 연결하면 사용 하십시오 .


파티에 늦었다는 건 알지만 이건 어때?

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

이렇게하면 enumchar*어레이 를 수동으로 동기화 할 필요가 없습니다 . 당신이 나와 같다면 나중에를 변경 enum하고 char*배열이 잘못된 문자열을 인쇄 할 가능성이 있습니다. 이것은 보편적으로 지원되는 기능이 아닐 수 있습니다. 그러나 대부분의 mordern day C 컴파일러는이 지정된 초기 스타일을 지원합니다.

여기에서 지정된 이니셜 라이저에 대해 자세히 읽을 수 있습니다 .


문제는 이름을 한 번만 쓰고 싶다는 것입니다.
다음과 같은 ider가 있습니다.

#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";
    }

구조체를 사용하여 enum을 삽입하므로 프린터에서 문자열로 각 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

The difference to enum is builder can not report error if the numbers are repeated. if you don't like write number, __LINE__ could replace it:

#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


i'm new to this but a switch statement will defenitely work

#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;
}

I like this to have enum in the dayNames. To reduce typing, we can do the following:

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

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

TheDay maps back to some integer type. So:

printf("%s", TheDay);

Attempts to parse TheDay as a string, and will either print out garbage or crash.

printf is not typesafe and trusts you to pass the right value to it. To print out the name of the value, you'd need to create some method for mapping the enum value to a string - either a lookup table, giant switch statement, etc.

참고URL : https://stackoverflow.com/questions/3168306/print-text-instead-of-value-from-c-enum

반응형