Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic method to display enum value names

Tags:

c++

c

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++?

like image 680
s_b Avatar asked Aug 11 '10 06:08

s_b


People also ask

How do you use generic enums?

The enum is a default subclass of the generic Enum<T> class, where T represents generic enum type. This is the common base class of all Java language enumeration types. The transformation from enum to a class is done by the Java compiler during compilation. This extension need not be stated explicitly in code.

Can enum be generic Java?

Java enums will be enhanced with generics support and with the ability to add methods to individual items, a new JEP shows. Since both features can be delivered with the same code change, they are bundled together in the same JEP. The change only affects the Java compiler, and therefore no runtime changes are needed.


1 Answers

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.

like image 185
schot Avatar answered Sep 27 '22 23:09

schot