你如何将值转换为 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.
要进一步扩展它,您可以执行一些预处理器巫术来自动生成映射数组(半)。但由于我不是预处理器巫术的好朋友,所以我会跳过它;)
之前我正在为我的解析器修复词法分析器;现在我必须为它创建一个验证器。我的想法是使用以下预处理器宏将枚举常量转换为字符串:#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.
要进一步扩展它,您可以执行一些预处理器巫术来自动生成映射数组(半)。但由于我不是预处理器巫术的好朋友,所以我会跳过它;)