3

So I'm trying to utilize Enumerated types in C for the first time. So I have an Enumerated "variable?" declared and I also have a struct which has a variable of the Enumerated type(among other things). Finally I have a static array for which there is an element containing each of the enum "types?" in the same order they were declared. I am hoping to use the enum type to act as an index for the array.

So my problem is that I need to somehow relate a char* variable to the enumerated type. If I KNOW that the Char* variable is one of the enum types, is there some way to assert that without having to look at each char to determine which specific enum"option" it is?

Example:

enum example = {abc,def}
struct _strExample {
       enum example letters;
       ....
};
typedef struct  _strExample strEx;
static strEx Table[2] = {
      {abc,...}
      {def,...}
};
//Given char* "abc" , want either example.abc or 0 ( correct index of table) 

So given the char* "abc"(does not need to be char*), is there a simple way to get either the correct enum "type?"(abc or def)or the correct index of the table? I know that I could check all the individual chars in the char* and manually determine which enumerated "type?" it is, but I am going to be working with a very large set of enumerated variables and this kind of thing is exactly what I was trying to avoid. any help or advice you guys could give on enumerated types and/or my design would be most appreciated.

  • Have you looked into using [gperf](https://www.gnu.org/software/gperf/)? – Mats Mar 27 '15 at 14:24
  • No, `enum` values must evaluate to integer values that are known at compile time, so strings (even though pointers will convert to integers) are out. You can use single characters, though, since `char` is an integral type. – Mike Housky Mar 27 '15 at 14:25
  • I have worked a little bit with hash tables in java, It seems like a good solution but I may only utilize things in the C standard library. –  Mar 27 '15 at 14:28
  • What's the matter with the solution in the last paragraph? In case you're afraid of performance penalties, make the lookup function inline, declare the table `const`, and the compiler should be able to optimize lookups of string literals (Gcc can, I've just tried). – mafso Mar 27 '15 at 14:34
  • There is nothing wrong with the solution I mentioned, I would just end up doing like 200 strcmp calls and I would prefer not to have to do that if there is an easier way –  Mar 27 '15 at 14:36
  • Well, this question isn't entirely clear, but as I understand it, that should be possible with one `strcmp` call in a loop. The function takes less than 5 lines. – mafso Mar 27 '15 at 14:41
  • Well if I have an enumerated "object?" with say 40 elements, I would need to compare a given char* with each of the variable names in the enumerated object (39 if I assume char* must be one). Can you iterate over an enum type in C? Is there a way to get an elements variable name as a char * given an index value of the enum object? –  Mar 27 '15 at 14:47
  • 1
    You can iterate over the `strEx` array, which contains the enum and possibly the `char *` (but I don't know, the code shown is incomplete). To get from the enum to the string, you can again iterate over `strEx` until you've found it. And no, you cannot iterate over an enum directly (there are some workarounds). – mafso Mar 27 '15 at 14:52

3 Answers3

4

Use a an array of strings where the index into the array is the enum value. If the strings are all short, or all about the same length, storing the string in the array makes sense. Otherwise, use a char* pointer.

typedef enum enum_t { plugh, plover, xyzzy, y0 } enum_t;
const char *etable = { "plugh", "plover", "xyxxy", "y0", NULL };

With that, you can convert with a simple search like:

enum_t find_enum(char *sval)
{
    enum_t result=plugh; /* value corresponding to etable[0] */
    int i=0;
    for (i=0; etable[i]!=NULL; ++i, ++result)
        if (0==strcmp(sval, etable[i])) return result;
    return -1;
}

The enum-to-string converstion is simply etable[e-plugh]. Those allow for a different definition of enum_t where the first meaningful value may not be 0, but the values are sequentially assigned thereafter.

Mike Housky
  • 3,959
  • 1
  • 17
  • 31
  • 2
    Good solution. But you have a small typo: `etable` should be a `char *etable[]`. Also, without a `typedef`, the type must be `enum enum_t` in C, with the `enum` keyword.. – M Oehm Mar 27 '15 at 14:53
  • This seems like the best solution, relating back to my example, I think I am just going to add a char *variable to my struct. so the table will be static strEx Table[2] = { {abc"abc",...} {def,"def",...} }; Thanks for the help –  Mar 27 '15 at 14:57
  • An addandum to this answer: [X macros](http://stackoverflow.com/questions/6635851/real-world-use-of-x-macros) might be a good way to keep enums and arrays in sync, if you don't mind the macro syntax (or using macros at all). – M Oehm Mar 27 '15 at 15:00
  • @MOehm Thanks for the corrections. I finally got around to adding them. The X macros link was interesting. I "invented" something very much like that technique back in 1986 (substituting the long, multi-line `#define` with a `#include` of those same lines. – Mike Housky Mar 30 '15 at 10:30
2

No, you can't lookup any scalar value from a character array. You have to iterate over a set of strings to compare and find the relation to the enum member.

You can use an array of structs

typedef struct { int value; const char * name; } lookup_t;

lookup_t lookup[] = { 
    { 1, "One"},
    { 0, NULL}   // end tag, alternatively use the _countof(lookup) to get the number of elements
};

and compare your char* with the name member. Then you use the value on match.

harper
  • 13,345
  • 8
  • 56
  • 105
0

Use if :

char *ex = "abc";
strEx strex;
if(!(strcmp("abc",ex))) {
    strex.letters = abc;
}
else {
    strex.letters = def;
}