【问题标题】:Converting from String to Enum in C在 C 中从字符串转换为枚举
【发布时间】:2013-05-30 19:50:14
【问题描述】:

是否有一种方便的方法来获取字符串(由用户输入)并将其转换为枚举值?在这种情况下,字符串将是枚举值的名称,如下所示:

enum Day
{
    Sunday = 0,
    Monday = 1,
    ...
}

因此,如果用户给出 Day 的名称,它就能够将其解析为相应的 Enum 值。

诀窍是,我正在使用超过 500 个值,它们分布在多个枚举中。

我知道 c# 中的 Enum.Parse 方法,那么 c 中是否有这种形式?

【问题讨论】:

标签: c string enums


【解决方案1】:

实现它的标准方法是:

typedef enum {value1, value2, value3, (...) } VALUE;

const static struct {
    VALUE      val;
    const char *str;
} conversion [] = {
    {value1, "value1"},
    {value2, "value2"},
    {value3, "value3"},
       (...)
};

VALUE
str2enum (const char *str)
{
     int j;
     for (j = 0;  j < sizeof (conversion) / sizeof (conversion[0]);  ++j)
         if (!strcmp (str, conversion[j].str))
             return conversion[j].val;    
     error_message ("no such string");
}

反之亦然。

【讨论】:

  • 老实说,我有点迷茫,你能澄清一下这是做什么的吗?
  • @Nealon:它建立了一个数据结构,将每个字符串值与相应的枚举值相关联。转换函数查找字符串匹配并返回相应的枚举值。
  • 就像用 C# 制作字典一样?
  • 可能是 const char *str; 而不是 char *str;。编译器可能会在此开发过程中检测到一些错误用途。
  • 值得注意的是,这个算法在可能的枚举值的数量上是 O(n)。如果你真的只是在一周中的几天,这会很好,但如果你有一个枚举,例如100 个可能的值,并且您多次调用此函数,它可能会加起来。
【解决方案2】:

没有直接的方法,但使用 C,你可以即兴发挥。这是一个老把戏。纯粹主义者可能会对此犹豫不决。但这是一种稍微理智地管理这类事情的方法。使用一些预处理器技巧。

在 constants.h 中输入以下内容:

CONSTANT(Sunday,  0)
CONSTANT(Monday,  1)
CONSTANT(Tuesday, 2)

在 main.c 中:

#include <stdio.h>

#define CONSTANT(name, value) \
    name = value,

typedef enum {
    #include "constants.h"
} Constants;

#undef CONSTANT

#define CONSTANT(name, value) \
    #name,

char* constants[] = {
    #include "constants.h"
};  

Constants str2enum(char* name) {
    int ii;
    for (ii = 0; ii < sizeof(constants) / sizeof(constants[0]); ++ii) {
        if (!strcmp(name, constants[ii])) {
            return (Constants)ii;
        }   
    }   
    return (Constants)-1;
}   

int main() {
    printf("%s = %d\n", "Monday", str2enum("Monday"));
    printf("%s = %d\n", "Tuesday", str2enum("Tuesday"));
    return 0;
}

您可以尝试基本思想的其他变体。

【讨论】:

  • +1。至于变体,如果您使用struct 将字符串关联到enum 值,您可以qsort() 数组,并使用bsearch() 进行查找。
  • 每当有人提到“预处理器技巧”时,我通常都会咬牙切齿,因为这样的关联代码通常很难阅读,也很难调试。我理解这种东西的吸引力,但同情那些不得不维护它的人。
  • 我喜欢它,但枚举是预定义的,我不能修改它们。
  • 是的,这种方法的吸引力在于实际上能够定义一个真正的枚举和一个字符串数组,它们会自动保持同步。否则,只需使用@wallyk 的回答。但是在你的工具箱中使用这种技术可能会很有用——尽管上面说了 wallyk :) 它实际上使事情变得更加清晰和可维护(一旦你了解发生了什么)。还有其他的可能性。就像在 switch 语句的上下文中扩展包含文件,实现调度程序等。有点像代码生成。
  • @wallyk 我的帖子在我看到你之前就已经挂了,不用担心,没有做出任何判断。
【解决方案3】:

警告,这是一个彻头彻尾的黑客攻击。您可以使用dlsym 来查找已适当初始化的变量。为了使这个示例能够工作,您必须进行编译以允许动态链接器可以看到局部符号。对于 GCC,选项是 -rdynamic

enum Day {
    SunDay, MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturDay
};

enum Day Sunday = SunDay,
         Monday = MonDay,
         Tuesday = TuesDay,
         Wednesday = WednesDay,
         Thursday = ThursDay,
         Friday = FriDay,
         Saturday = SaturDay;

int main () {
    const char *daystr = "Thursday";
    void *h = dlopen(0, RTLD_NOW);
    enum Day *day = dlsym(h, daystr);
    if (day) printf("%s = %d\n", daystr, *day);
    else printf("%s not found\n", daystr);
    return 0;
}

【讨论】:

  • 大胆!但是在我懒惰的时候可以派上用场。
【解决方案4】:

并非如此,但如果您使用散列函数,您可以设置枚举的所有值以匹配一组散列字符串。如果您不关心区分大小写,则可能必须使用更复杂的哈希。

这可能是您最好的解决方案,因为它的开销低于 strcmp (...)。从字符串哈希分配枚举值不需要重复的字符串比较等...

【讨论】:

  • 使用哈希肯定是最便宜的选择,从这个规模来看,我认为这将是要走的路。我必须为每个枚举生成单独的哈希函数。
【解决方案5】:

如果您使用的是直接 C,则没有“Enum.Parse”等效项。您需要编写自己的函数,将用户的字符串与带有strcmp() 的预定义值进行比较,然后返回适当的枚举值。

另一种可能性是使用现有的“哈希映射”实现,或者滚动您自己的实现 - 例如,glib 中的那个应该适合您:https://developer.gnome.org/glib/2.30/glib-Hash-Tables.html

哈希映射应该比对可能的枚举值进行线性搜索更快,如果你有很多枚举值(例如,如果你做的事情不是一周中的几天)。一个好的哈希映射实现应该接近于 O(1) 的查找,而不是 O(n) 的线性搜索。

【讨论】:

  • 我正在使用的多个枚举中有 500 多个值。我会更新我的问题以反映这一点。
【解决方案6】:

这将是一个很好的解决方案:

enum e_test { a, b, c, END };

enum e_test get_enum_value(char * val) {
    static char const * e_test_str[] = { "a", "b", "c" };
    for (int i = 0; i < END; ++i)
        if (!strcmp(e_test_str[i], val))
            return i;
    return END;
 }

【讨论】:

    猜你喜欢
    • 2010-09-06
    • 2015-06-10
    • 2012-08-25
    • 1970-01-01
    • 2013-01-23
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 2010-10-03
    相关资源
    最近更新 更多