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?
126 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.
6There 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.
6Warning, 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; } 1Not 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...
1If 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.
1That 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; }