在C中为typedef枚举添加预定义数据
为C中的typedef枚举定义其他数据的最佳方法是什么?
例子:
typedef enum { kVizsla = 0, kTerrier = 3, kYellowLab = 10 } DogType;
现在,我想为每个名称定义名称,例如," kVizsla"应为" vizsla"。
我目前使用一个使用大开关块返回字符串的函数。
解决方案
回答
这是一个开放式的问题,但是一个建议是使用以枚举为键类型并在值中包含额外信息的映射。 (与示例不同,如果索引是连续的,则可以使用序列容器而不是映射)。
回答
如果枚举值足够密集,则可以定义一个数组来保存字符串并仅对其进行查找(对于任何跳过的值,请使用NULL,并在查找例程中添加特殊情况处理程序)。
char *DogList[] = { "vizsla", /* element 0 */ NULL, NULL, NULL, "terrier", /* element 3 */ ... };
这对于稀疏枚举效率低下。
即使枚举不密集,也可以使用结构数组来保存映射。
typedef struct DogMaps { DogType index; char * name; } DogMapt; DogMapt DogMap[] = { {kVizsla, "vizsla"}, {kTerrier, "terrier"}, {kYellowLab, "yellow lab"}, NULL };
第二种方法非常灵活,但是它的确意味着我们每次需要使用数据时都通过映射进行搜索。对于大型数据集,请考虑使用b树或者哈希而不是数组。
可以将这两种方法通用化以连接更多数据。第一种使用结构数组,第二种使用结构中添加更多成员。
当然,我们将需要编写各种处理程序来简化与这些数据结构的交互。
@Hershi一定要分开代码和数据。以上示例是为了清楚而不是功能。
我很脸红,承认我仍然为此目的使用空格分隔的平面文件,而不是我们展示的结构化输入,但是我的生产代码将尽可能多地从外部源读取数据。
等等,我看到意思是代码生成。
当然。没有错。
我怀疑,尽管OP对生成的代码应该是什么样的感兴趣...
回答
@dmckee:我认为建议的解决方案很好,但是对于简单数据(例如,仅需要名称),可以使用自动生成的代码进行扩充。尽管有很多方法可以自动生成代码,但是对于如此简单的事情,我相信我们可以编写一个简单的XSLT,该XSLT接受枚举的XML表示并输出代码文件。
XML的形式为:
<EnumsDefinition> <Enum name="DogType"> <Value name="Vizsla" value="0" /> <Value name="Terrier" value="3" /> <Value name="YellowLab" value="10" /> </Enum> </EnumsDefinition>
结果代码将类似于dmckee在其解决方案中建议的内容。
有关如何编写这样的XSLT的信息,请尝试在这里或者只是在google中搜索并找到适合的教程。编写XSLT在IMO上并不是一件很有趣的事情,但也没有那么糟糕,至少对于诸如此类的相对简单的任务而言也是如此。
回答
非常适合X()宏。这些类型的宏可以使用C预处理器从同一源构造枚举和数组。我们只需要向包含X()宏的#define中添加新数据即可。
示例可以编写如下:
// All dog data goes in this list #define XDOGTYPE \ X(kVizsla,0,"vizsla") \ X(kTerrier,3,"terrier") \ X(kYellowLab,10,"yellowlab") // Dog info typedef struct { int val; // Defined value char * desc; // Text description } DogType; // Build an array index using the Names typedef enum { #define X(Name,Val,Text) Name, XDOGTYPE #undef X MAXDOGS } DogIndex; // Build a lookup table of values DogType Dog[] = { #define X(Name,Val,Text) {Val,Text}, XDOGTYPE #undef X }; // Access the values for (i=0; i < MAXDOGS; i++) printf("%d: %s\n",Dog[i].val,Dog[i].desc);