zxc*_*xcv 86 c enums c-preprocessor
这是我想要做的:
typedef enum { ONE, TWO, THREE } Numbers;
Run Code Online (Sandbox Code Playgroud)
我正在尝试编写一个函数来执行类似于以下的切换案例:
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;
}
Run Code Online (Sandbox Code Playgroud)
而不是在每种情况下定义,有没有办法使用枚举变量设置它,就像我在上面尝试做的那样?
Sum*_*uma 65
从使某些东西成为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 */ \
} \
Run Code Online (Sandbox Code Playgroud)
someEnum.h:
#include "enumFactory.h"
#define SOME_ENUM(XX) \
XX(FirstValue,) \
XX(SecondValue,) \
XX(SomeOtherValue,=50) \
XX(OneMoreValue,=100) \
DECLARE_ENUM(SomeEnum,SOME_ENUM)
Run Code Online (Sandbox Code Playgroud)
someEnum.cpp:
#include "someEnum.h"
DEFINE_ENUM(SomeEnum,SOME_ENUM)
Run Code Online (Sandbox Code Playgroud)
该技术可以很容易地扩展,以便XX宏接受更多的参数,并且您还可以准备更多的宏来代替XX以满足不同的需求,类似于我在此示例中提供的三个.
虽然这与其他人提到的X-Macros类似,但我认为这个解决方案更优雅,因为它不需要#undefing任何东西,它允许你隐藏更多复杂的东西,在工厂的头文件 - 头文件当你需要定义一个新的枚举时,你完全没有触及它,因此新的枚举定义更短更清晰.
Bil*_*ter 61
// 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
Run Code Online (Sandbox Code Playgroud)
sk.*_*sk. 14
没有内置的解决方案.最简单的方法是使用一个数组,char*
其中enum的int值索引到包含该枚举的描述性名称的字符串.如果你有一个稀疏enum
(一个不是从0开始或在编号中有间隙),其中一些int
映射足够高,使得基于数组的映射不切实际,那么你可以使用哈希表代替.
Jay*_*ayG 13
肯定有一种方法可以做到这一点 - 使用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;
Run Code Online (Sandbox Code Playgroud)
有更有效的方法(即使用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]);
}
Run Code Online (Sandbox Code Playgroud)
C或C++不提供此功能,但我经常需要它.
以下代码有效,但它最适合非稀疏枚举.
typedef enum { ONE, TWO, THREE } Numbers;
char *strNumbers[] = {"one","two","three"};
printf ("Value for TWO is %s\n",strNumbers[TWO]);
Run Code Online (Sandbox Code Playgroud)
非稀疏,我的意思不是形式
typedef enum { ONE, FOUR_THOUSAND = 4000 } Numbers;
Run Code Online (Sandbox Code Playgroud)
因为那里有巨大的差距.
这种方法的优点是它使枚举和字符串的定义彼此接近; 在函数中使用switch语句可以表示它们.这意味着你不太可能在没有另一个的情况下改变一个.
吻.您将使用您的枚举做各种其他开关/案例的事情,那么为什么打印会有所不同?如果您认为大约有100个其他地方可以忘记案件,那么忘记打印例程中的案例并不是一件大事.只需编译-Wall,它将警告非详尽的案例匹配.不要使用"默认",因为这样可以使开关彻底,并且您不会收到警告.相反,让开关退出并处理默认情况,如此...
const char *myenum_str(myenum e)
{
switch(e) {
case ONE: return "one";
case TWO: return "two";
}
return "invalid";
}
Run Code Online (Sandbox Code Playgroud)