[英]A proper way of associating enums with 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"
}
我經常遇到的另一個:
typedef enum {
STRING_HELLO,
STRING_WORLD
} string_enum_type;
const char *string_enumerations[] = {
[STRING_HELLO] = "Hello",
[STRING_WORLD] = "World"
}
這兩種方法的缺點是什么? 還有更好的嗎?
前者的唯一優勢是它與古老的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");
以上是簡單的“枚舉 - 查找表”耦合的最佳方法。 另一種選擇是使用結構,但這更適合更復雜的數據類型。
最后,更多的是作為旁注,第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");
另一種可能是使用函數而不是數組:
const char *enumtostring(string_enum_type e) {
switch(e) {
case STRING_HELLO: return "hello";
case STRING_WORLD: return "world";
}
}
至少gcc會在添加枚舉值時發出警告,但忘記添加匹配的switch case。
(我想你也可以嘗試inline
這種功能。)
附錄:我提到的海灣合作委員會警告僅當switch
語句沒有一個default
情況下。 因此,如果你想打印一些以某種方式蠕變的越界值的東西,你可以這樣做,而不是default
情況,但是有這樣的東西:
const char *enumtostring(string_enum_type e) {
switch(e) {
case STRING_HELLO: return "hello";
case STRING_WORLD: return "world";
}
return "(unrecognized string_enum_type value)";
}
包含越界值也很好:
static char tmpbuf[50];
snprintf(tmpbuf, sizeof(tmpbuf), "(unrecognized string_enum_type value %d)", e);
return tmpbuf;
(這最后一個片段有一些額外的限制,但是這個附錄已經很久了,所以我現在不會對它們提出異議。)
另一種可能性是用戶#defines
。
盡管使用了許多缺點,但主要的好處是#defines
不占用空間,除非它們被使用......
#define STRING_HELLO "Hello"
#define STRING_WORLD "World"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.