代码之家  ›  专栏  ›  技术社区  ›  CIsForCookies

返回枚举的名称而不是其值

  •  4
  • CIsForCookies  · 技术社区  · 6 年前

    枚举中有一组值。作为一个例子,我选择了 WEEK_DAY (我的实际案例有许多(50+)值,它们不是连续的( 1000,1001,2000,... ):

    typedef enum{
      SUNDAY,
      MONDAY,
      FRIDAY = 6
    }WEEK_DAY;
    

    我现在要创建一个函数,给定 星期四 值,将返回其名称。我通过使用:

    #define STRING_REPLACE(x) #x
    
    char *value_2_name(WEEK_DAY day)
    {
           switch(day)
           {
           case SUNDAY:
                           return STRING_REPLACE(SUNDAY);
           case MONDAY:
                           return STRING_REPLACE(MONDAY);
           case FRIDAY:
                           return STRING_REPLACE(FRIDAY);
           }
    }
    

    并称之为 printf("%s", value_2_name(6)); / printf("%s", value_2_name(FRIDAY)); 会按预期打印出“星期五”。

    有没有办法把这个函数压缩成一行?

    即以某种方式在参数之间进行替换 WEEK_DAY day 以及 enum WEEK_DAY 对应项,然后使用 STRING_REPLACE ?

    我要找的是: STRING_REPLACE(day_2_WEEK_DAY_enum )

    某些枚举具有强制值,因此无法使用 How to convert enum names to string in c

    3 回复  |  直到 6 年前
        1
  •  3
  •   Antti Haapala -- Слава Україні    6 年前

    不是一行代码,但您可以使用标准兼容的C编译器(C99+)和 an X macro 为此:

    #define STRINGIFY(x) #x
    #define WEEKDAYS \
        X(SUNDAY,) \
        X(MONDAY,) \
        X(FRIDAY, = 6)
    
    typedef enum {
        #define X(name, init) name init,
        WEEKDAYS
        #undef X
    } Weekday;
    
    char *weekday_lookup[] = {
        #define X(name, init) [name] = STRINGIFY(name),
        WEEKDAYS
        #undef X
    };
    

    这将机械地产生以下代码:

    typedef enum {
    
        SUNDAY , MONDAY , FRIDAY = 6,
    
    } Weekday;
    
    char *weekday_lookup[] = {
    
        [SUNDAY] = "SUNDAY", [MONDAY] = "MONDAY", [FRIDAY] = "FRIDAY",
    
    };
    

    另一种方法是,如果查找表太大或不可编译(索引太大或为负值),或者如果需要c89,则构建一个包含值、名称对的表,并对其进行迭代。


    如果你不喜欢写反睫毛或长 #define s,您可以为x数据库使用include文件:

    工作日定义公司 :

    X(SUNDAY,)
    X(MONDAY,)
    X(FRIDAY, = 6)
    

    实际使用:

    typedef enum {
        #define X(name, init) name init,
        #include "weekday_def.inc"
        #undef X
    } Weekday;
    
    char *weekday_lookup[] = {
        #define X(name, init) [name] = STRINGIFY(name),
        #include "weekday_def.inc"
        #undef X
    };
    
        2
  •  2
  •   pm101    6 年前

    你的解决方案已经很好了,因为它太简单了。我想问题是当枚举数变得很大的时候。我认为除了调用函数之外,没有其他方法可以在一行中完成这项工作。正如一些程序员所说,C没有内省功能。所以你得自己弥补。我做了一个枚举结构。它将处理枚举中的间距——但是您可能会意识到 仅仅是执行这个功能就变得多么复杂和可笑。

    #ifndef __ENUM_H__
    #define __ENUM_H__
    
    #define null 0x00
    
    #define ENUM_MAX_VALUES 4
    #define ENUM_MAX_SCHEMA 4
    #define ENUM_MAX_ENUM 4
    #define ENUM_MAX_STRING_LEN 16
    
    /**
    * enum_key_value_t is essentially a key/value pair
    * the key is the integer, the value is the string
    */
    typedef struct
    {
        /** integer enum value */
        int key;
        /** string enum value */
        char value[ENUM_MAX_STRING_LEN];
    }enum_key_value_t;
    /**
    * An enum schema contains all possible string/int pairs
    */
    typedef struct
    {
        /** all possible values of the enumerator object */
        enum_key_value_t values[ENUM_MAX_VALUES];
        /** the number of values used out of MAX_ENUM_VALUES */
        int num_values;
    }enum_schema_t;
    
    typedef struct
    {
        /** current value of the enumerator object */
        enum_key_value_t *value;
        enum_schema_t *schema;
    }enum_t;
    
    enum_schema_t *new_EnumSchema(void);
    
    void EnumSchema_AddValue(enum_schema_t *e, int key, const char *value);
    enum_key_value_t *Enum_SetValue(enum_t *e, int key);
    const char *Enum_GetValue(enum_t *e);
    enum_t *new_Enum(enum_schema_t *schema, int initial_value);
    
    #endif
    

    C语言

    #include "enum.h"
    #include <string.h>
    #include <stdio.h>
    /** used in place of null strings etc. */
    const char g_UNDEFINED[] = "<<UNDEFINED>>";
    /** All enumerator objects */
    static enum_schema_t g_EnumSchemas[ENUM_MAX_SCHEMA];
    static enum_t g_Enums[ENUM_MAX_ENUM];
    
    /** Current number of enumerator objects */
    static int g_num_EnumSchemas = 0;
    static int g_num_Enums = 0;
    
    static enum_key_value_t *Enum_FindValue(enum_schema_t *e, int key);
    
    /**
    * new_Enum
    *
    * create a new enumerator
    *
    * @return pointer to the new enumerator
    */
    enum_schema_t *new_EnumSchema(void)
    {
        if (g_num_EnumSchemas < ENUM_MAX_SCHEMA)
        {
            enum_schema_t *ret = &g_EnumSchemas[g_num_EnumSchemas++];
    
            ret->num_values = 0;
    
            return ret;
        }
    
        return null;
    }
    
    /**
    * new_Enum
    *
    * create a new enumerator
    *
    * @return pointer to the new enumerator
    */
    enum_t *new_Enum(enum_schema_t *schema, int initial_value)
    {
        if (g_num_Enums < ENUM_MAX_ENUM)
        {
            enum_t *ret = &g_Enums[g_num_Enums++];
    
            ret->schema = schema;
            ret->value = Enum_FindValue(schema, initial_value);
    
            return ret;
        }
    
        return null;
    }
    /**
    * Enum_AddValue
    *
    * adds a value/key key to a enumerator object
    *
    * @param e pointer to the enumerator object
    * @param key the enumerated byte key
    * @param value the value to show for this key
    */
    void EnumSchema_AddValue(enum_schema_t *e, int key, const char *value)
    {
        if (e->num_values < ENUM_MAX_VALUES)
        {
            int i;
            enum_key_value_t *val = &e->values[e->num_values++];
    
            val->key = key;
    
            strncpy(val->value, value, ENUM_MAX_STRING_LEN - 1);
    
            val->value[ENUM_MAX_STRING_LEN - 1] = 0;
        }
    }
    /**
    * Enum_SetValue
    *
    * changes the enumerated key
    *
    * @param e pointer to the enumerator object
    * @param key the new enumerated byte key
    * @return pointer to the enum_key_value_t object that contains the key
    */
    enum_key_value_t *Enum_SetValue(enum_t *e, int key)
    {
        enum_key_value_t *val = Enum_FindValue(e->schema, key);
    
        if (val != null)
        {
            e->value = val;
    
            return val;
        }
    
        return null;
    }
    /**
    * Enum_GetValue
    *
    * gets the enumerated value key for enumerated key
    *
    * @param e pointer to the enumerator object
    * @return value key
    */
    const char *Enum_GetValue(enum_t *e)
    {
        if (e->value != null)
            return e->value->value;
    
        return g_UNDEFINED;
    }
    
    /*************************************
    * STATIC FUNCTIONS (Local functions)
    *************************************/
    
    /**
    * Enum_FindValue
    *
    * finds the enumerated key
    *
    * @param e pointer to the enumerator object
    * @param key the enumerated byte key
    * @return pointer to enum_key_value_t object that contains the key
    */
    static enum_key_value_t *Enum_FindValue(enum_schema_t *e, int key)
    {
        int i;
    
        for (i = 0; i < e->num_values; i++)
        {
            enum_key_value_t *val = &e->values[i];
    
            if (val->key == key)
                return val;
        }
    
        return null;
    }
    

    主C

    #include <stdio.h>
    
    #include "enum.h"
    
    typedef enum
    {
        SUNDAY,
        MONDAY,
        FRIDAY = 6
    }WEEK_DAY;
    
    enum_schema_t *week_day_init()
    {
        enum_schema_t *enum_weekday = new_EnumSchema();
    
        // add possible values
        EnumSchema_AddValue(enum_weekday, SUNDAY, "SUNDAY");
        EnumSchema_AddValue(enum_weekday, MONDAY, "MONDAY");
        EnumSchema_AddValue(enum_weekday, FRIDAY, "FRIDAY");
    
        return enum_weekday;
    }
    
    void main()
    {
        enum_schema_t *week_day_enum_t = week_day_init();
    
        enum_t *weekday1 = new_Enum(week_day_enum_t, SUNDAY);
    
        // the 'one-liner'
        printf("weekday1 is currently '%s'\n",Enum_GetValue(weekday1));
    
        Enum_SetValue(weekday1, FRIDAY);
    
        printf("weekday1 is now '%s'\n", Enum_GetValue(weekday1));
    
    }
    

    输出

    weekday1 is currently 'SUNDAY'
    weekday1 is now 'FRIDAY'
    
        3
  •  1
  •   izac89    6 年前

    丑陋,不可维护,效率不高,但完全按照您的要求:

    #define ENUMS()  \
    ENTRY(SUNDAY, 0) \
    ENTRY(MONDAY, 1) \
    ENTRY(FRIDAY, 6)
    
    typedef enum{
    #define ENTRY(_enum, _val) _enum = _val,
    ENUMS()
    #undef ENTRY
    }WEEK_DAY;
    
    #define MAX_STR_LEN 7
    char days_str[][MAX_STR_LEN]={
    #define ENTRY(_enum, _val) #_enum,
    ENUMS()
    #undef ENTRY
    };
    
    char* value_2_name(WEEK_DAY day)
    {
        return days_str[day - ((1U - (((unsigned int)(day - sizeof(days_str)/MAX_STR_LEN))>>31))
                                        *
                                      (day - (sizeof(days_str)/MAX_STR_LEN) ) )
                            - (1U - (((unsigned int)(day - sizeof(days_str)/MAX_STR_LEN))>>31))] ; 
    }
    

    它支持所描述的非连续枚举值,它使用最小的字符串数组- char* 本例中的数组大小为21字节,仅包含3个字符串, 没有“洞” (计算数组索引的原因)但不应被人类使用。