7

Is there a way to display the name of an enum's value? say we have:

enum fuits{
    APPLE,
    MANGO,
    ORANGE,
};

main(){
enum fruits xFruit = MANGO;
...
printf("%s",_PRINT_ENUM_STRING(xFruit));
...
}

using the preprocessor

#define _PRINT_ENUM_STRING(x) #x

won't work as we need to get the value of the variable 'x' and then convert It to string. Is this at all possible in c/C++?

s_b
  • 501
  • 5
  • 16
  • Possible duplicate http://stackoverflow.com/questions/3342726/c-print-out-enum-value-as-text – Eugen Constantin Dinca Aug 11 '10 at 07:04
  • 1
    This is a FAQ all over the intertubes and mostly likely a dupe here, although I did not check. Answer: no, it cannot be done (without jumoing through hoops such as @Naveen suggests and running the risk of getting out of synch. If you are prepared to take that risk a nunber of people seem to use this solution. It's better than nothing, but it's tempting fate ...). – Mawg says reinstate Monica Aug 11 '10 at 07:10
  • @Eugen Constantin Dinca That question is C++ only, while the OP here seems to want a C solution. – schot Aug 11 '10 at 07:10
  • @schot This question was tagged C++ by the OP. – Eugen Constantin Dinca Aug 11 '10 at 07:13
  • Gee! thanks for the comments, i too thought it couldn't be done either. Well, just to make sure as C keeps amazing me every other day. i guess i'll mark schot as the closest answer then. – s_b Aug 11 '10 at 07:15
  • @Eugen Constantin Dinca OK, didn't know it was retagged and the example code looked very C to me. – schot Aug 11 '10 at 07:23

4 Answers4

7

You could use the preprocessor to do this, I believe this technique is called X-Macros:

/* fruits.def */
X(APPLE)
X(MANGO)
X(ORANGE)

/* file.c */
enum fruits {
#define X(a) a,
#include "fruits.def"
#undef X
};

const char *fruit_name[] = {
#define X(a) #a,
#include "fruits.def"
#undef X
};

Note that the last entry includes a trailing comma, which is allowed in C99 (but not in C89). If that is a problem you can add sentinal values. It is also possible to make the macro more complicated by giving multiple arguments for custom names or enum values, etc:

X(APPLE, Apple, 2)
#define X(a,b,c) a = c,        /* in enum */
#define X(a,b,c) [c] = #b,     /* in name array */

Limitations: You cannot have negative constants and your array is sizeof (char *) * largest_constant. But you could work around both by using an extra lookup table:

int map[] = {
#define X(a,b,c) c,
#include "fruits.def"
#undef X
};

This doesn't work of course. What does work is generating an extra set of enum constants as keys for the names:

enum fruits {
#define X(a,b,c) a ## _KEY,
#include "fruits.def"
#undef X
#define X(a,b,c) a = c,
#include "fruits.def"
#undef X
};

Now you can find the name of X(PINEAPPLE, Pineapple, -40) by using fruit_name[PINEAPPLE_KEY].

People noted that they didn't like the extra include file. You don't need this extra file, you also use a #define. This may be more appropriate for small lists:

#define FRUIT_LIST X(APPLE) X(ORANGE)

And replace #include "fruits.def with FRUIT_LIST in the previous examples.

schot
  • 10,958
  • 2
  • 46
  • 71
  • This is the best way I know. I've used a similar technique for error strings with a 2-argument X macro: `X(name,desc)` where the macro expanded to either the error code (analogous to `errno` values) or a descriptive string depending on where the error list file was included. – R.. GitHub STOP HELPING ICE Aug 11 '10 at 07:11
  • 1
    +1. This nearly beats my usual hack of defining the enum in a perl script that writes the enum to a .h file and the matching translation array to a .c file. My way requires a custom build step which is easy with make, but harder in a full IDE. – RBerteig Aug 11 '10 at 07:38
  • I don't like it. Can be useful sometimes, but I would not overuse it. Maybe I would use it for big and frequently changed enums. The costs of this are too big. – adf88 Aug 11 '10 at 08:28
  • ...Extra header file, scattered includes, use of preprocessor. You can make mistakes because of them. For small and medium enums it's better to write the lookup table by yourself, near the enum declaration. – adf88 Aug 11 '10 at 08:36
  • ...There are techniques that reduce a risk of lookup table being desynchronized like defining inside an enum the first and the last markers, then putting static assert on lookup table size depending on these markers. Usually these markers are helpful for other purposes so this is not an additional mess just to keep lookup table synchronized. – adf88 Aug 11 '10 at 08:42
  • @adf88 See added last paragraph for a version without extra header files or scattered includes. – schot Aug 11 '10 at 08:47
  • That's better :). Anyway, this is worth to be mentioned solution. – adf88 Aug 11 '10 at 08:50
1

You can use a mapping in this case.

char *a[10] = { "APPLE","MANGO","ORANGE"};

printf("%s",a[xFruit]);

Yes the preprocessor won't work unless you provide the exact enum -value.

Also check this question for more insights.

Community
  • 1
  • 1
Praveen S
  • 10,355
  • 2
  • 43
  • 69
0

I've used preprocessor programming successfully to get a macro of this kind:

DEFINE_ENUM(Fruits, (Apple)(Mango)(Orange));

It does a tad more than just printing the names, but it could easily be simplified to 2 switches if necessary.

It's based on Boost.Preprocessor facilities (notably BOOST_PP_SEQ_FOREACH) which is a must have for preprocessor programming, and I find it much more elegant than the X facility and its file reinclusion system.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
-1

 public enum LDGoalProgressUpdateState
    {

    [Description("Yet To Start")]
    YetToStart = 1,
    [Description("In Progress")]
    InProgress = 2,
    [Description("Completed")]
    Completed = 3
}


    var values = (ENUMList[])Enum.GetValues(typeof(ENUMList));
    var query = from name in values
                select new EnumData//EnumData is a Modal or Entity
                {
                    ID = (short)name,
                    Name = GetEnumDescription(name)//Description of Particular Enum Name
                };
    return query.ToList();

region HelperMethods

public static string GetEnumDescription(Enum value) { FieldInfo fi = value.GetType().GetField(value.ToString()); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); if (attributes != null && attributes.Length > 0) return attributes[0].Description; else return value.ToString(); } #endregion