How to convert enum names to string in c How to convert enum names to string in c c c

How to convert enum names to string in c


One way, making the preprocessor do the work. It also ensures your enums and strings are in sync.

#define FOREACH_FRUIT(FRUIT) \        FRUIT(apple)   \        FRUIT(orange)  \        FRUIT(grape)   \        FRUIT(banana)  \#define GENERATE_ENUM(ENUM) ENUM,#define GENERATE_STRING(STRING) #STRING,enum FRUIT_ENUM {    FOREACH_FRUIT(GENERATE_ENUM)};static const char *FRUIT_STRING[] = {    FOREACH_FRUIT(GENERATE_STRING)};

After the preprocessor gets done, you'll have:

enum FRUIT_ENUM {    apple, orange, grape, banana,};static const char *FRUIT_STRING[] = {    "apple", "orange", "grape", "banana",};

Then you could do something like:

printf("enum apple as a string: %s\n",FRUIT_STRING[apple]);

If the use case is literally just printing the enum name, add the following macros:

#define str(x) #x#define xstr(x) str(x)

Then do:

printf("enum apple as a string: %s\n", xstr(apple));

In this case, it may seem like the two-level macro is superfluous, however, due to how stringification works in C, it is necessary in some cases. For example, let's say we want to use a #define with an enum:

#define foo appleint main() {    printf("%s\n", str(foo));    printf("%s\n", xstr(foo));}

The output would be:

fooapple

This is because str will stringify the input foo rather than expand it to be apple. By using xstr the macro expansion is done first, then that result is stringified.

See Stringification for more information.


In a situation where you have this:

enum fruit {    apple,     orange,     grape,    banana,    // etc.};

I like to put this in the header file where the enum is defined:

static inline char *stringFromFruit(enum fruit f){    static const char *strings[] = { "apple", "orange", "grape", "banana", /* continue for rest of values */ };    return strings[f];}


I found a C preprocessor trick that is doing the same job without declaring a dedicated array string (Source: http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/c_preprocessor_applications_en).

Sequential enums

Following the invention of Stefan Ram, sequential enums (without explicitely stating the index, e.g. enum {foo=-1, foo1 = 1}) can be realized like this genius trick:

#include <stdio.h>#define NAMES C(RED)C(GREEN)C(BLUE)#define C(x) x,enum color { NAMES TOP };#undef C#define C(x) #x,    const char * const color_name[] = { NAMES };

This gives the following result:

int main( void )  {     printf( "The color is %s.\n", color_name[ RED ]);      printf( "There are %d colors.\n", TOP ); }

The color is RED.
There are 3 colors.

Non-Sequential enums

Since I wanted to map error codes definitions to are array string, so that I can append the raw error definition to the error code (e.g. "The error is 3 (LC_FT_DEVICE_NOT_OPENED)."), I extended the code in that way that you can easily determine the required index for the respective enum values:

#define LOOPN(n,a) LOOP##n(a)#define LOOPF ,#define LOOP2(a) a LOOPF a LOOPF#define LOOP3(a) a LOOPF a LOOPF a LOOPF#define LOOP4(a) a LOOPF a LOOPF a LOOPF a LOOPF#define LOOP5(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF#define LOOP6(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF#define LOOP7(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF#define LOOP8(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF#define LOOP9(a) a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF a LOOPF#define LC_ERRORS_NAMES \    Cn(LC_RESPONSE_PLUGIN_OK, -10) \    Cw(8) \    Cn(LC_RESPONSE_GENERIC_ERROR, -1) \    Cn(LC_FT_OK, 0) \    Ci(LC_FT_INVALID_HANDLE) \    Ci(LC_FT_DEVICE_NOT_FOUND) \    Ci(LC_FT_DEVICE_NOT_OPENED) \    Ci(LC_FT_IO_ERROR) \    Ci(LC_FT_INSUFFICIENT_RESOURCES) \    Ci(LC_FT_INVALID_PARAMETER) \    Ci(LC_FT_INVALID_BAUD_RATE) \    Ci(LC_FT_DEVICE_NOT_OPENED_FOR_ERASE) \    Ci(LC_FT_DEVICE_NOT_OPENED_FOR_WRITE) \    Ci(LC_FT_FAILED_TO_WRITE_DEVICE) \    Ci(LC_FT_EEPROM_READ_FAILED) \    Ci(LC_FT_EEPROM_WRITE_FAILED) \    Ci(LC_FT_EEPROM_ERASE_FAILED) \    Ci(LC_FT_EEPROM_NOT_PRESENT) \    Ci(LC_FT_EEPROM_NOT_PROGRAMMED) \    Ci(LC_FT_INVALID_ARGS) \    Ci(LC_FT_NOT_SUPPORTED) \    Ci(LC_FT_OTHER_ERROR) \    Ci(LC_FT_DEVICE_LIST_NOT_READY)#define Cn(x,y) x=y,#define Ci(x) x,#define Cw(x)enum LC_errors { LC_ERRORS_NAMES TOP };#undef Cn#undef Ci#undef Cw#define Cn(x,y) #x,#define Ci(x) #x,#define Cw(x) LOOPN(x,"")static const char* __LC_errors__strings[] = { LC_ERRORS_NAMES };static const char** LC_errors__strings = &__LC_errors__strings[10];

In this example, the C preprocessor will generate the following code:

enum LC_errors { LC_RESPONSE_PLUGIN_OK=-10,  LC_RESPONSE_GENERIC_ERROR=-1, LC_FT_OK=0, LC_FT_INVALID_HANDLE, LC_FT_DEVICE_NOT_FOUND, LC_FT_DEVICE_NOT_OPENED, LC_FT_IO_ERROR, LC_FT_INSUFFICIENT_RESOURCES, LC_FT_INVALID_PARAMETER, LC_FT_INVALID_BAUD_RATE, LC_FT_DEVICE_NOT_OPENED_FOR_ERASE, LC_FT_DEVICE_NOT_OPENED_FOR_WRITE, LC_FT_FAILED_TO_WRITE_DEVICE, LC_FT_EEPROM_READ_FAILED, LC_FT_EEPROM_WRITE_FAILED, LC_FT_EEPROM_ERASE_FAILED, LC_FT_EEPROM_NOT_PRESENT, LC_FT_EEPROM_NOT_PROGRAMMED, LC_FT_INVALID_ARGS, LC_FT_NOT_SUPPORTED, LC_FT_OTHER_ERROR, LC_FT_DEVICE_LIST_NOT_READY, TOP };static const char* __LC_errors__strings[] = { "LC_RESPONSE_PLUGIN_OK", "" , "" , "" , "" , "" , "" , "" , "" "LC_RESPONSE_GENERIC_ERROR", "LC_FT_OK", "LC_FT_INVALID_HANDLE", "LC_FT_DEVICE_NOT_FOUND", "LC_FT_DEVICE_NOT_OPENED", "LC_FT_IO_ERROR", "LC_FT_INSUFFICIENT_RESOURCES", "LC_FT_INVALID_PARAMETER", "LC_FT_INVALID_BAUD_RATE", "LC_FT_DEVICE_NOT_OPENED_FOR_ERASE", "LC_FT_DEVICE_NOT_OPENED_FOR_WRITE", "LC_FT_FAILED_TO_WRITE_DEVICE", "LC_FT_EEPROM_READ_FAILED", "LC_FT_EEPROM_WRITE_FAILED", "LC_FT_EEPROM_ERASE_FAILED", "LC_FT_EEPROM_NOT_PRESENT", "LC_FT_EEPROM_NOT_PROGRAMMED", "LC_FT_INVALID_ARGS", "LC_FT_NOT_SUPPORTED", "LC_FT_OTHER_ERROR", "LC_FT_DEVICE_LIST_NOT_READY", };

This results to the following implementation capabilities:

LC_errors__strings[-1] ==> LC_errors__strings[LC_RESPONSE_GENERIC_ERROR] ==> "LC_RESPONSE_GENERIC_ERROR"