简体   繁体   English

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

[英]return enum's name instead of its value

I have a set of values in an enum. 我在枚举中有一组值。 As an example I chose WEEK_DAY (my actual case has many (50+) values, and they are not-continuous ( 1000,1001,2000,... )): 作为一个例子,我选择了WEEK_DAY (我的实际案例有很多(50+)个值,它们不是连续的( 1000,1001,2000,... )):

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

I now want to create a function that, given a WEEK_DAY value, would return its name. 我现在想要创建一个函数,给定WEEK_DAY值,它将返回其名称。 I done this by using: 我这样做是通过使用:

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

And calling it with printf("%s", value_2_name(6)); 并使用printf("%s", value_2_name(6));调用它printf("%s", value_2_name(6)); / printf("%s", value_2_name(FRIDAY)); / printf("%s", value_2_name(FRIDAY)); would print out "FRIDAY" as expected. 将按预期打印出“星期五”。

Is there a way to squeeze this function into a one line? 有没有办法将此功能压缩成一行?

ie to somehow make the substitution between parameter WEEK_DAY day and its enum WEEK_DAY counterpart, and then use the STRING_REPLACE ? 即以某种方式在参数WEEK_DAY day它的enum WEEK_DAY对应物之间进行替换,然后使用STRING_REPLACE

What I'm looking for is something like: STRING_REPLACE(day_2_WEEK_DAY_enum ) 我正在寻找的是: STRING_REPLACE(day_2_WEEK_DAY_enum

Some enums have forced values so it's not possible to use answers from How to convert enum names to string in c 一些枚举有强制值,所以不可能使用如何将枚举名称转换为c中的字符串的答案

Not really one line, but you can use a standard-compliant C compiler (C99+) and an X macro for this: 不是一行,但你可以使用符合标准的C编译器(C99 +)和X宏

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

This will mechanistically produce the following code: 这将机械地产生以下代码:

typedef enum {

    SUNDAY , MONDAY , FRIDAY = 6,

} Weekday;

char *weekday_lookup[] = {

    [SUNDAY] = "SUNDAY", [MONDAY] = "MONDAY", [FRIDAY] = "FRIDAY",

};

Another way, if a lookup table would become too large or not compilable (too large index or negative values), or if C89 is required, is to build a table of value, name pairs that will be iterated over. 另一种方法是,如果查找表变得太大或不可编译(索引或负值太大),或者需要C89,则构建一个值表,将重复使用名称对。


If you don't like writing backlashes or long #define s, you can use an include file for the X-database: 如果您不喜欢编写反斜杠或长#define ,则可以使用包含X文件数据库的文件:

weekday_def.inc : weekday_def.inc

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

Actual use: 实际使用:

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

Your solution is pretty good already as it is simplistic. 你的解决方案非常好,因为它很简单。 I guess the problem is when the enums get pretty big. 我想问题是当枚举变得非常大时。 I don't think there is a way to do this in one line except call a function. 除了调用函数之外,我认为没有办法在一行中执行此操作。 As 'some programmer dude' said, C doesn't have introspection features. 正如'某些程序员老兄'所说,C没有内省特征。 So you've got to make it up yourself. 所以你必须自己做好准备。 I made an enum structure to do this. 我做了一个枚举结构来做到这一点。 It will work with spacing in the enum-- however you may realize how complicated and ridiculous it gets, just to perform this function. 它将与枚举中的间距一起工作 - 但是你可能会发现它变得多么复杂和荒谬,只是为了执行这个功能。

enum.h enum.h

#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

enum.c enum.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;
}

main.c main.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));

}

output 产量

weekday1 is currently 'SUNDAY'
weekday1 is now 'FRIDAY'

Ugly, un-maintainable and not efficient, but does exactly what you asked for: 丑陋,不可维护且效率不高,但完全符合您的要求:

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

It supports non continuous enum values as depicted, it uses minimal string arrays- the char* array in this example is of size 21 bytes, contains only 3 strings, no "holes" (the reason for the calculation of the array index) but should not be used by humans. 它支持非连续的枚举值,如图所示,它使用最小的字符串数组 - 本例中的char*数组大小为21个字节,只包含3个字符串, 没有“漏洞” (计算数组索引的原因)但应该不被人类使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM