C语言中的通用枚举到文本查找

Maw*_*awg 3 c enums pointers

[更新]

  1. 给出的代码确实有效.当我认为它没有时,我错了.我的错; 遗憾++.如果您可以改进代码,请访问https://codereview.stackexchange.com/questions/150480/generic-enum-to-text-lookup-in-c
  2. 我们必须在编译时声明我们的字符串.我们对嵌入式系统进行编码,不允许使用malloc().很抱歉没有这么清楚.

[更新++]我可能会接受下面的答案之一.但是,我忘了说,我们的枚举是非连续的,并且范围很广,这可以有所作为


intertubes和这个网站充斥着要求从枚举中获取文本的问题.

我找不到一个规范的方法来做这个(并且会接受一个作为这个问题的答案),所以让我们看看我们是否可以在我们之间拼凑一个.

在我们的代码中,我们有多个结构数组,包含枚举对应和相应的字符串.

问题是字符串具有不同的长度,因此我们为每个字符串编写一个查找函数,用于在结构数组上循环,尝试匹配枚举并在找到匹配时返回相应的文本.

让我们采取以下两个人为的例子:

// +=+=+=+=+=+=+=+=+=+=+=+=+=+=
typedef enum
{
    north,
    south,
    east,
    west
} E_directions;

struct direction_datum
{
    E_directions direction;
    char         direction_name[6];
};

struct direction_datum direction_data[] =
{
    {north, "north"},
    {south, "south"},
    {east,  "east"},
    {west,  "west"},
};

// +=+=+=+=+=+=+=+=+=+=+=+=+=+=
typedef enum
{
    hearts,
    spades,
    diamonds,
    clubs,
} E_suits;

struct suit_datum
{
    E_suits suit;
    char    suit_name[9];
};

struct suit_datum suit_data[] =
{
    {hearts,   "hearts"},
    {spades,   "spades"},
    {diamonds, "diamonds",},
    {clubs,    "clubs"},
};
Run Code Online (Sandbox Code Playgroud)

除了字符串长度,它们是相似/相同的,因此,理论上,我们应该能够编写泛型函数来循环遍历direction_data或suit_data给定索引并返回相应的文本.

我正在考虑这样的事情 - 但是它不起作用(结构中的枚举值似乎总是为零,所以显然我的指针算法是关闭的).

我做错了什么?

char *Get_text_from_enum(int enum_value, 
                         void *array, 
                         unsigned int array_length, 
                         unsigned int size_of_array_entry)
{
    unsigned int i;
    unsigned int offset;

    for (i = 0; i < array_length; i++)
    {
        offset = i * size_of_array_entry;

        if ((int) * ((int *) (array+ offset)) == enum_value)
            return (char *)  (array + offset + sizeof(int));
    }

    return NULL;
}


printf("Expect south,    got %s\n", 
          Get_text_from_enum(south,    
                             direction_data, 
                             ARRAY_LENGTH(direction_data),  
                             sizeof(direction_data[0])));

printf("Expect diamonds, got %s\n", 
          Get_text_from_enum(diamonds, 
                             suit_data,      
                             ARRAY_LENGTH(suit_data),       
                             sizeof(suit_data[0])));
Run Code Online (Sandbox Code Playgroud)

Lun*_*din 5

有两种"规范"方法可以做到这一点.一个是可读的,一个避免代码重复.


可读的方式

"可读方式"是我推荐的.它使用相应的查找表构建枚举,其中枚举常量与查找表索引匹配:

typedef enum
{
    north,
    south,
    east,
    west,
    directions_n // only used to keep track of the amount of enum constants
} direction_t;

const char* STR_DIRECTION [] =  // let array size be based on number of items
{
  "north",
  "south",
  "east",
  "west"
};


#define ARRAY_ITEMS(array) (sizeof(array) / sizeof(*array))
...
// verify integrity of enum and look-up table both:
_Static_assert(directions_n == ARRAY_ITEMS(STR_DIRECTION), 
               "direction_t does not match STR_DIRECTION");
Run Code Online (Sandbox Code Playgroud)

如果你愿意,你仍然可以有一个基于此的结构:

typedef struct
{
  direction_t dir;
  const char* str;
} dir_struct_t;

const dir_struct_t DIRS [directions_n] = 
{ // use designated initializers to guarantee data integrity even if item order is changed:
  [north] = {north, STR_DIRECTION[north]},
  [south] = {south, STR_DIRECTION[south]},
  [east]  = {east,  STR_DIRECTION[east]},
  [west]  = {west,  STR_DIRECTION[west]}
};
Run Code Online (Sandbox Code Playgroud)

没有代码重复的方式

另一种选择是使用所谓的"X-macros",除了作为最后的手段之外,它并不是真正推荐的,因为它们往往使代码严重不可读,特别是那些没有在这些宏上使用的代码.

此代码等同于上面的示例:

#define DIRECTION_LIST \
  X(north), \
  X(south), \
  X(east),  \
  X(west),         // trailing commma important here! (and ok in enums since C99)

typedef enum
{
  #define X(dir) dir
    DIRECTION_LIST
  #undef X
  directions_n // only used to keep track of the amount of enum constants
} direction_t;

typedef struct
{
  direction_t dir;
  const char* str;
} dir_struct_t;

const dir_struct_t DIRS [directions_n] = 
{
  #define X(dir) {dir, #dir}
    DIRECTION_LIST
  #undef X
};
Run Code Online (Sandbox Code Playgroud)

这个宏版本摆脱了显式字符串查找表.

  • @Mawg此处发布的内容现在属于SO而不属于我.我认为你可以使用它,但我不是软件许可证的专家.在Meta上可能有一些信息. (2认同)