这是我想要做的:
typedef enum { ONE, TWO, THREE } Numbers;
我正在尝试编写一个函数来执行类似于以下的切换案例:
char num_str[10]; int process_numbers_str(Numbers num) { switch(num) { case ONE: case TWO: case THREE: { strcpy(num_str, num); //some way to get the symbolic constant name in here? } break; default: return 0; //no match return 1; }
而不是在每种情况下定义,有没有办法使用枚举变量设置它,就像我在上面尝试做的那样?
从使某些东西成为C标识符和字符串的技术?可以在这里使用.
像往常一样使用这样的预处理器东西,编写和理解预处理器部分可能很难,并且包括将宏传递给其他宏并涉及使用#和##运算符,但使用它真的很容易.我觉得这种风格对长枚举非常有用,两次保持相同的列表真的很麻烦.
enumFactory.h:
// expansion macro for enum value definition #define ENUM_VALUE(name,assign) name assign, // expansion macro for enum to string conversion #define ENUM_CASE(name,assign) case name: return #name; // expansion macro for string to enum conversion #define ENUM_STRCMP(name,assign) if (!strcmp(str,#name)) return name; /// declare the access function and define enum values #define DECLARE_ENUM(EnumType,ENUM_DEF) \ enum EnumType { \ ENUM_DEF(ENUM_VALUE) \ }; \ const char *GetString(EnumType dummy); \ EnumType Get##EnumType##Value(const char *string); \ /// define the access function names #define DEFINE_ENUM(EnumType,ENUM_DEF) \ const char *GetString(EnumType value) \ { \ switch(value) \ { \ ENUM_DEF(ENUM_CASE) \ default: return ""; /* handle input error */ \ } \ } \ EnumType Get##EnumType##Value(const char *str) \ { \ ENUM_DEF(ENUM_STRCMP) \ return (EnumType)0; /* handle input error */ \ } \
someEnum.h:
#include "enumFactory.h" #define SOME_ENUM(XX) \ XX(FirstValue,) \ XX(SecondValue,) \ XX(SomeOtherValue,=50) \ XX(OneMoreValue,=100) \ DECLARE_ENUM(SomeEnum,SOME_ENUM)
someEnum.cpp:
#include "someEnum.h" DEFINE_ENUM(SomeEnum,SOME_ENUM)
该技术可以很容易地扩展,以便XX宏接受更多的参数,并且您还可以准备更多的宏来代替XX以满足不同的需求,类似于我在此示例中提供的三个.
虽然这与其他人提到的X-Macros类似,但我认为这个解决方案更优雅,因为它不需要#undefing任何东西,它允许你隐藏更多复杂的东西,在工厂的头文件 - 头文件当你需要定义一个新的枚举时,你完全没有触及它,因此新的枚举定义更短更清晰.
// Define your enumeration like this (in say numbers.h); ENUM_BEGIN( Numbers ) ENUM(ONE), ENUM(TWO), ENUM(FOUR) ENUM_END( Numbers ) // The macros are defined in a more fundamental .h file (say defs.h); #define ENUM_BEGIN(typ) enum typ { #define ENUM(nam) nam #define ENUM_END(typ) }; // Now in one and only one .c file, redefine the ENUM macros and reinclude // the numbers.h file to build a string table #undef ENUM_BEGIN #undef ENUM #undef ENUM_END #define ENUM_BEGIN(typ) const char * typ ## _name_table [] = { #define ENUM(nam) #nam #define ENUM_END(typ) }; #undef NUMBERS_H_INCLUDED // whatever you need to do to enable reinclusion #include "numbers.h" // Now you can do exactly what you want to do, with no retyping, and for any // number of enumerated types defined with the ENUM macro family // Your code follows; char num_str[10]; int process_numbers_str(Numbers num) { switch(num) { case ONE: case TWO: case THREE: { strcpy(num_str, Numbers_name_table[num]); // eg TWO -> "TWO" } break; default: return 0; //no match return 1; } // Sweet no ? After being frustrated by this for years, I finally came up // with this solution for my most recent project and plan to reuse the idea // forever
没有内置的解决方案.最简单的方法是使用一个数组,char*
其中enum的int值索引到包含该枚举的描述性名称的字符串.如果你有一个稀疏enum
(一个不是从0开始或在编号中有间隙),其中一些int
映射足够高,使得基于数组的映射不切实际,那么你可以使用哈希表代替.
肯定有一种方法可以做到这一点 - 使用X()宏.这些宏使用C预处理器从源数据列表构造枚举,数组和代码块.您只需要向包含X()宏的#define添加新项.switch语句会自动扩展.
您的示例可以编写如下:
// Source data -- Enum, String #define X_NUMBERS \ X(ONE, "one") \ X(TWO, "two") \ X(THREE, "three") ... // Use preprocessor to create the Enum typedef enum { #define X(Enum, String) Enum, X_NUMBERS #undef X } Numbers; ... // Use Preprocessor to expand data into switch statement cases switch(num) { #define X(Enum, String) \ case Enum: strcpy(num_str, String); break; X_NUMBERS #undef X default: return 0; break; } return 1;
有更有效的方法(即使用X宏创建字符串数组和枚举索引),但这是最简单的演示.
我知道你有几个很好的答案,但你知道C预处理器中的#运算符吗?
它可以让你这样做:
#define MACROSTR(k) #k typedef enum { kZero, kOne, kTwo, kThree } kConst; static char *kConstStr[] = { MACROSTR(kZero), MACROSTR(kOne), MACROSTR(kTwo), MACROSTR(kThree) }; static void kConstPrinter(kConst k) { printf("%s", kConstStr[k]); }
C或C++不提供此功能,但我经常需要它.
以下代码有效,但它最适合非稀疏枚举.
typedef enum { ONE, TWO, THREE } Numbers; char *strNumbers[] = {"one","two","three"}; printf ("Value for TWO is %s\n",strNumbers[TWO]);
非稀疏,我的意思不是形式
typedef enum { ONE, FOUR_THOUSAND = 4000 } Numbers;
因为那里有巨大的差距.
这种方法的优点是它使枚举和字符串的定义彼此接近; 在函数中使用switch语句可以表示它们.这意味着你不太可能在没有另一个的情况下改变一个.
吻.您将使用您的枚举做各种其他开关/案例的事情,那么为什么打印会有所不同?如果您认为大约有100个其他地方可以忘记案件,那么忘记打印例程中的案例并不是一件大事.只需编译-Wall,它将警告非详尽的案例匹配.不要使用"默认",因为这样可以使开关彻底,并且您不会收到警告.相反,让开关退出并处理默认情况,如此...
const char *myenum_str(myenum e) { switch(e) { case ONE: return "one"; case TWO: return "two"; } return "invalid"; }