How to convert an enum type variable to a string?

How to make printf to show the values of variables which are of an enum type? For instance:

typedef enum {Linux, Apple, Windows} OS_type; 
OS_type myOS = Linux;

and what I need is something like

printenum(OS_type, "My OS is %s", myOS);

which must show a string "Linux", not an integer.

I suppose, first I have to create a value-indexed array of strings. But I don't know if that is the most beautiful way to do it. Is it possible at all?


The naive solution, of course, is to write a function for each enumeration that performs the conversion to string:

enum OS_type { Linux, Apple, Windows };

inline const char* ToString(OS_type v)
{
    switch (v)
    {
        case Linux:   return "Linux";
        case Apple:   return "Apple";
        case Windows: return "Windows";
        default:      return "[Unknown OS_type]";
    }
}

This, however, is a maintenance disaster. With the help of the Boost.Preprocessor library, which can be used with both C and C++ code, you can easily take advantage of the preprocessor and let it generate this function for you. The generation macro is as follows:

#include <boost/preprocessor.hpp>

#define X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE(r, data, elem)    \
    case elem : return BOOST_PP_STRINGIZE(elem);

#define DEFINE_ENUM_WITH_STRING_CONVERSIONS(name, enumerators)                \
    enum name {                                                               \
        BOOST_PP_SEQ_ENUM(enumerators)                                        \
    };                                                                        \
                                                                              \
    inline const char* ToString(name v)                                       \
    {                                                                         \
        switch (v)                                                            \
        {                                                                     \
            BOOST_PP_SEQ_FOR_EACH(                                            \
                X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE,          \
                name,                                                         \
                enumerators                                                   \
            )                                                                 \
            default: return "[Unknown " BOOST_PP_STRINGIZE(name) "]";         \
        }                                                                     \
    }

The first macro (beginning with X_) is used internally by the second. The second macro first generates the enumeration, then generates a ToString function that takes an object of that type and returns the enumerator name as a string (this implementation, for obvious reasons, requires that the enumerators map to unique values).

In C++ you could implement the ToString function as an operator<< overload instead, but I think it's a bit cleaner to require an explicit "ToString" to convert the value to string form.

As a usage example, your OS_type enumeration would be defined as follows:

DEFINE_ENUM_WITH_STRING_CONVERSIONS(OS_type, (Linux)(Apple)(Windows))

While the macro looks at first like it is a lot of work, and the definition of OS_type looks rather foreign, remember that you have to write the macro once, then you can use it for every enumeration. You can add additional functionality to it (e.g., a string-form to enum conversion) without too much trouble, and it completely solves the maintenance problem, since you only have to provide the names once, when you invoke the macro.

The enumeration can then be used as if it were defined normally:

#include <iostream>

int main()
{
    OS_type t = Windows;
    std::cout << ToString(t) << " " << ToString(Apple) << std::endl;
}

The code snippets in this post, beginning with the #include <boost/preprocessor.hpp> line, can be compiled as posted to demonstrate the solution.

This particular solution is for C++ as it uses C++-specific syntax (e.g., no typedef enum) and function overloading, but it would be straightforward to make this work with C as well.


There really is no beautiful way of doing this. Just set up an array of strings indexed by the enum.

If you do a lot of output, you can define an operator<< that takes an enum parameter and does the lookup for you.


This is the pre processor block

#ifndef GENERATE_ENUM_STRINGS
    #define DECL_ENUM_ELEMENT( element ) element
    #define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
    #define END_ENUM( ENUM_NAME ) ENUM_NAME; \
            char* getString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
    #define DECL_ENUM_ELEMENT( element ) #element
    #define BEGIN_ENUM( ENUM_NAME ) char* gs_##ENUM_NAME [] =
    #define END_ENUM( ENUM_NAME ) ; char* getString##ENUM_NAME(enum \
            tag##ENUM_NAME index){ return gs_##ENUM_NAME [index]; }
#endif

Enum definition

BEGIN_ENUM(OsType)
{
    DECL_ENUM_ELEMENT(WINBLOWS),
    DECL_ENUM_ELEMENT(HACKINTOSH),
} END_ENUM(OsType)

Call using

getStringOsType(WINBLOWS);

Taken from here. How cool is that ? :)


Use std::map<OS_type, std::string> and populate it with enum as key, and string representation as values, then you can do these:

printf("My OS is %s", enumMap[myOS].c_str());
std::cout << enumMap[myOS] ;