Converting from String to Enum in C

Converting from String to Enum in C

Is there a convienent way to take a string (input by user) and convert it to an Enumeration value? In this case, the string would be the name of the enumeration value, like so:

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

So that if the user gave the name of a Day, it would be able to parse that to the corresponding Enum value.

The trick is, I have over 500 values I'm working with, and they are spread out across multiple enumerations.

I know of the Enum.Parse Method in c#, so is there some form of this in c?

12

6 Answers

The standard way to implement it is something along the lines of:

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

The converse should be apparent.

6

There isn't a direct way, but with C, you improvise. Here's an old trick. Purists may balk at this. But it's a way to manage this kind of stuff somewhat sanely. Uses some preprocessor tricks.

In constants.h put in the following:

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

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

You can try other variations of the basic idea.

6

Warning, this is a total hack. You can use dlsym to do a lookup of a variable that is appropriately initialized. For this example to work, you have to compile to allow local symbols to be visible to the dynamic linker. With GCC, the option is -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;
}
1

Not really, though if you use a hash function you can setup all of the values of your enum to match a set of hashed strings. You might have to use a more complicated hash if you don't care about case-sensitivity.

This is probably your best solution, since it has lower overhead than strcmp (...). The assignment of an enum value from a string hash does not require repeated string comparisons, etc...

1

If you're using straight C, there isnt a "Enum.Parse" equivalent. You'll want to write your own function, comparing the user's string to pre-defined values with strcmp(), and then returning the appropriate enum value.

Another possibility is using an existing "hash map" implementation, or rolling your own - for instance, the one in glib should work for you:

A hash map should be faster than doing a linear search on the possible enum values, if you have a lot of them (for instance, if you were doing something other than the days of the week). A good hash map implementation should be close to O(1) for lookups, instead of O(n) for a linear search.

1

That would be a good solution :

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

James H. Sterling
Author

James H. Sterling

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.