You can use a preprocessor for this, I believe this method is called X-Macros :
X(APPLE) X(MANGO) X(ORANGE) 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 contains the trailing comma, which is allowed in C99 (but not in C89). If this is a problem, you can add valuable values. It is also possible to make a macro more complex by providing a few arguments for user names or enumeration values, etc.:
X(APPLE, Apple, 2) #define X(a,b,c) a = c, #define X(a,b,c) [c] = #b,
Limitations: you cannot have negative constants, and your array is sizeof (char *) * largest_constant . But you can get around both with an optional lookup table:
int map[] = { #define X(a,b,c) c, #include "fruits.def" #undef X };
Strike>
This does not work, of course. What makes the job of generating an additional set of enum constants as keys for 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 X(PINEAPPLE, Pineapple, -40) using fruit_name[PINEAPPLE_KEY] .
People noted that they did not like the optional include file. You do not need this additional file, you also use #define . This may be more suitable for small lists:
#define FRUIT_LIST X(APPLE) X(ORANGE)
And replace #include "fruits.def with FRUIT_LIST in the previous examples.