如何将值转换为c中的枚举常量?

时间:2015-01-05 22:49:41

标签: c enums

早些时候我正在为我的解析器修复词法分析器;现在我必须为它创建一个验证器。我的想法是使用以下预处理器宏将枚举常量转换为字符串:#define MACRO_STRINGIFY(x) #x

然后我做了一个函数来比较各种令牌值,我做了三个,但它们都是一样的,只有一些小的改动):

unsigned int compare_keyword( enum script_keywords keyword, char *token ) {
  char *temporary = MACRO_STRINGIFY( keyword );
  unsigned int i = 0;
  for (; i < (strlen( "KEYWORD_" ) + 1); i++) {
    ++temporary;
  }
  // 0 on match, 1 on no match
  return strcmp( temporary, token ) ? 1 : 0;
}

现在,这个功能绝对正常... 当关键字是枚举常量时:

void test() {
  printf( "\nIF is " );
  // Finish the sentence based on the return value
  compare_keyword( KEYWORD_IF, "IF" ) ? printf( "not a keyword.\n" ) : printf( "a keyword.\n" );
}
test(); //--> Outputs 'IF is a keyword' like expected.

另一方面,如果我传递一个像1这样的值(符号枚举常量KEYWORD_IF解析为的值),则该函数不能按预期工作。

// Same as last time with one edit:
void test() {
  /* See above code with following change on line 4 */
  compare_keyword( 1, "IF" ) /* etc... */
  /* Rest of code from previous test */
}
test(); //--> Outputs 'IF is not a keyword' even if KEYWORD_IF resolves to the value 1.

我在这里得到的一点是,preproccessor是非常文字的,我更喜欢使用for循环来有效地循环遍历常量而不会使代码大小膨胀(如果我最终使用的话会发生这种情况)枚举常量)。因此,问题是我如何使用switch…case…if…else…将纯整数值转换为符号名称而不是

编辑:枚举详细信息:

enum script_keywords {
  KEYWORD_IF = 1,
  KEYWORD_THEN = 2,
  KEYWORD_ELSEIF = 3,
  KEYWORD_ELSE = 4,
  KEYWORD_ENDIF = 5,
  KEYWORD_FOR = 6,
  KEYWORD_TO = 7,
  KEYWORD_STEP = 8,
  KEYWORD_EXITFOR = 9,
  KEYWORD_NEXT = 10,
  KEYWORD_LOOP = 11,
  KEYWORD_WHILE = 12,
  KEYWORD_EXITLOOP = 13,
  KEYWORD_ENDLOOP = 14,
  KEYWORD_DO = 15,
  KEYWORD_EXITDO = 16,
  KEYWORD_UNTIL = 17,
  KEYWORD_ON = 18,
  KEYWORD_GOTO = 19,
  KEYWORD_CALL = 20,
  KEYWORD_LET = 21,
  KEYWORD_DIM = 22,
  KEYWORD_AS = 23
};

1 个答案:

答案 0 :(得分:0)

The Macro&#34; MACRO_STRINGIFY&#34;由预处理器在编译时进行评估。它将返回参数的实际名称,所以

MACRO_STRINGIFY(keyword) -> "keyword"
MACRO_STRINGIFY(KEYWORD_IF) -> "KEYWORD_IF"
MACRO_STRINGIFY(1) -> "1"

显然这不会导致任何解决方案。

相反,可以使用编译时生成的键值映射来实现此类功能:

struct map
{
  int key;
  const char* value;
};

struct map mappings[] =
{
  { KEYWORD_IF, "IF" },
  { KEYWORD_ELSE, "ELSE" }
};

然后在运行时简单地迭代这些映射条目以找出你需要的东西:

static int is_keyword(const char* str)
{
  int i;
  const int count = sizeof(mappings) / sizeof(mappings[0]);

  for(i = 0; i < count; i++)
  {
    struct map* m = &mappings[i];

    if(strcmp(str, m->value) == 0)
    {
      return 1;
    }
  }

  return 0;
}

void test()
{
  const char* str = "IF";
  const char* what;

  if(is_keyword(str))
  {
    what = "a keyword";
  }
  else
  {
    what = "not a keyword";
  }

  printf("%s is %s.\n", str, what);
}

这可能是最小的。可执行二进制文件通常不包括从例如已知的枚举值的名称。 Java的。

为了进一步扩展,你可以做一些预处理器voodoo自动生成映射数组(半)。但由于我不是预处理器伏都教的大朋友,我会跳过它;)