Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
189 views
in Technique[技术] by (71.8m points)

Easy way to use variables of enum types as string in C?

Here's what I am trying to do:

typedef enum { ONE, TWO, THREE } Numbers;

I am trying to write a function that would do a switch case similar to the following:

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;
}

Instead of defining at every case, is there a way to set it using the enum variable like I am trying to do above?

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The technique from Making something both a C identifier and a string? can be used here.

As usual with such preprocessor stuff, writing and understanding the preprocessor part can be hard, and includes passing macros to other macros and involves using # and ## operators, but using it is real easy. I find this style very useful for long enums, where maintaining the same list twice can be really troublesome.

Factory code - typed only once, usually hidden in the header:

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 */ 
  } 

Factory used

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)

The technique can be easily extended so that XX macros accepts more arguments, and you can also have prepared more macros to substitute for XX for different needs, similar to the three I have provided in this sample.

Comparison to X-Macros using #include / #define / #undef

While this is similar to X-Macros others have mentioned, I think this solution is more elegant in that it does not require #undefing anything, which allows you to hide more of the complicated stuff is in the factory the header file - the header file is something you are not touching at all when you need to define a new enum, therefore new enum definition is a lot shorter and cleaner.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...