将枚举与字符串关联的正确方法

PoV*_*oVa 19 c enums c-strings

假设我在整个程序中经常使用一些字符串(用于存储状态和类似的东西).字符串操作可能很昂贵,所以无论何时解决它们我都想使用枚举.到目前为止,我已经看到了几个解决方案:

typedef enum {
    STRING_HELLO = 0,
    STRING_WORLD
} string_enum_type;

// Must be in sync with string_enum_type
const char *string_enumerations[] = {
    "Hello",
    "World"
}
Run Code Online (Sandbox Code Playgroud)

我经常遇到的另一个:

typedef enum {
    STRING_HELLO,
    STRING_WORLD
} string_enum_type;

const char *string_enumerations[] = {
    [STRING_HELLO] = "Hello",
    [STRING_WORLD] = "World"
}
Run Code Online (Sandbox Code Playgroud)

这两种方法的缺点是什么?还有更好的吗?

Lun*_*din 14

前者的唯一优势是它与古老的C标准向后兼容.

除此之外,后一种选择是优越的,因为它确保数据完整性,即使枚举被修改或项目改变位置.但是,它应该通过检查来完成,以确保枚举中的项目数与查找表中的项目数相对应:

typedef enum {
    STRING_HELLO,
    STRING_WORLD,
    STRING_N  // counter
} string_enum_type;

const char *string_enumerations[] = {
    [STRING_HELLO] = "Hello",
    [STRING_WORLD] = "World"
};

_Static_assert(sizeof string_enumerations/sizeof *string_enumerations == STRING_N,
               "string_enum_type does not match string_enumerations");
Run Code Online (Sandbox Code Playgroud)

以上是简单的"枚举 - 查找表"耦合的最佳方法.另一种选择是使用结构,但这更适合更复杂的数据类型.


最后,更多的是作为旁注,第3版将是使用"X宏".除非您对代码重复和维护有特殊要求,否则不建议这样做.为了完整起见,我会将其包含在此处,但我不建议在一般情况下使用它:

#define STRING_LIST          \
 /* index         str    */  \
  X(STRING_HELLO, "Hello")   \
  X(STRING_WORLD, "World")


typedef enum {
  #define X(index, str) index,
    STRING_LIST
  #undef X
  STRING_N // counter
} string_enum_type;


const char *string_enumerations[] = {
  #define X(index, str) [index] = str,
    STRING_LIST
  #undef X
};

_Static_assert(sizeof string_enumerations/sizeof *string_enumerations == STRING_N,
               "string_enum_type does not match string_enumerations");
Run Code Online (Sandbox Code Playgroud)