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

How do you convert values to enumeration constants in c?

之前我正在为我的解析器修复词法分析器;现在我必须为它创建一个验证器。我的想法是使用以下预处理器宏将枚举常量转换为字符串:#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.

我在这里得到的要点是预处理器是非常直接的,我更喜欢使用 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
};

宏 "MACRO_STRINGIFY" 在编译时由预处理器计算。它将 return 参数的实际名称,因此

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.

要进一步扩展它,您可以执行一些预处理器巫术来自动生成映射数组(半)。但由于我不是预处理器巫术的好朋友,所以我会跳过它;)