C语言 从 C 枚举打印文本而不是值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3168306/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:47:32  来源:igfitidea点击:

Print text instead of value from C enum

cenums

提问by avi

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

回答by Tyler McHenry

Enumerations in C are numbers that have convenient names inside your code. They are not strings, and the names assigned to them in the source code are not compiled into your program, and so they are not accessible at runtime.

C 中的枚举是在代码中具有方便名称的数字。它们不是字符串,源代码中分配给它们的名称不会编译到您的程序中,因此在运行时无法访问它们。

The only way to get what you want is to write a function yourself that translates the enumeration value into a string. E.g. (assuming here that you move the declaration of enum Daysoutside of main):

获得所需内容的唯一方法是自己编写一个函数,将枚举值转换为字符串。例如,(这里假设你移动的声明enum Daysmain):

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

Alternatively, you could use an array as a map, e.g.

或者,您可以使用数组作为地图,例如

const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };

/* ... */

printf("%s", dayNames[TheDay]);

But here you would probably want to assign Sunday = 0in the enumeration to be safe... I'm not sure if the C standard requires compilers to begin enumerations from 0, although most do (I'm sure someone will comment to confirm or deny this).

但是在这里您可能希望Sunday = 0在枚举中进行分配以确保安全...我不确定 C 标准是否要求编译器从 0 开始枚举,尽管大多数都这样做(我确定有人会评论以确认或否认这一点)。

回答by Vargas

I use something like this:

我使用这样的东西:

in a file "EnumToString.h":

在文件“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

then in any header file you make the enum declaration, day enum.h

然后在任何头文件中进行枚举声明,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)

then in a file called EnumToString.c:

然后在一个名为 EnumToString.c 的文件中:

#include "enum.h"

#define GENERATE_ENUM_STRINGS  // Start string generation

#include "enum.h"             

#undef GENERATE_ENUM_STRINGS   // Stop string generation

then in main.c:

然后在 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;
}

this will generate "automatically" the strings for any enums declared this way and included in "EnumToString.c"

这将为以这种方式声明并包含在“EnumToString.c”中的任何枚举“自动”生成字符串

回答by casablanca

The way I usually do this is by storing the string representations in a separate array in the same order, then indexing the array with the enum value:

我通常这样做的方法是将字符串表示形式以相同的顺序存储在一个单独的数组中,然后使用枚举值索引数组:

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

回答by jdmichal

Enumerations in C are basically syntactical sugar for named lists of automatically-sequenced integer values. That is, when you have this code:

C 中的枚举基本上是自动排序的整数值命名列表的语法糖。也就是说,当你有这个代码时:

int main()
{
    enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};

    Days TheDay = Monday;
}

Your compiler actually spits out this:

你的编译器实际上吐出了这个:

int main()
{
    int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}

Therefore, outputting a C enumeration as a string is not an operation that makes sense to the compiler. If you want to have human-readable strings for these, you will need to define functions to convert from enumerations to strings.

因此,将 C 枚举作为字符串输出对于编译器来说不是有意义的操作。如果您想为这些提供人类可读的字符串,则需要定义函数以将枚举转换为字符串。

回答by Tim Schaeffer

Here's a cleaner way to do it with 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;
}

I'm not sure that this is totally portable b/w preprocessors, but it works with gcc.

我不确定这是否是完全可移植的黑白预处理器,但它适用于 gcc。

This is c99 btw, so use c99 strictif you plug it into (the online compiler) ideone.

这是 c99 btw,所以c99 strict如果你把它插入(在线编译器)ideone 中使用

回答by Mark Elliot

enums in C don't really work the way you're expecting them to. You can think of them kind of like glorified constants (with a few additional benefits relating to being a collectionof such constants), and the text you've written in for "Sunday" really gets resolved to a number during compilation, the text is ultimately discarded.

enumC 中的 s 并没有真正按照您期望的方式工作。你可以把它们想象成美化的常量(作为这些常量的集合还有一些额外的好处),你为“星期日”写的文本在编译过程中真的被解析为一个数字,文本是最终被丢弃。

In short: to do what you really want you'll need to keep an array of the strings or create a function to map from the enum's value to the text you'd like to print.

简而言之:要执行您真正想要的操作,您需要保留一个字符串数组或创建一个函数以将枚举值映射到您想要打印的文本。

回答by fortytwo

I know I am late to the party, but how about this?

我知道我参加聚会迟到了,但是这个怎么样?

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

This way, you do not have to manually keep the enumand the char*array in sync. If you are like me, chances are that you will later change the enum, and the char*array will print invalid strings. This may not be a feature universally supported. But afaik, most of the mordern day C compilers support this designated initialier style.

这样,您不必手动保持enumchar*阵列同步。如果您像我一样,以后可能会更改enum,并且char*数组将打印无效字符串。这可能不是普遍支持的功能。但是 afaik,大多数现代 C 编译器都支持这种指定的初始化样式。

You can read more about designated initializers here.

您可以在此处阅读有关指定初始值设定项的更多信息。

回答by user8931844

The question is you want write the name just one times.
I have an ider like this:

问题是你只想写一次名字。
我有一个像这样的 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";
    }

it uses a struct to insert enum, so that a printer to string could follows each enum value define.

它使用一个结构来插入枚举,以便打印机到字符串可以跟随每个枚举值定义。

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

>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:

与 enum 的区别在于,如果数字重复,builder 不会报告错误。如果你不喜欢写数字,__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

>day Wednesday, number is 3>day Monday, number is 1

回答by Heng lou

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

我喜欢在 dayNames 中有枚举。为了减少打字,我们可以执行以下操作:

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

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

回答by Suraj K Thomas

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

我是新手,但 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;
}