Easy way to use variables of enum types as string in C?
There's no built-in solution. The easiest way is with an array of char*
where the enum's int value indexes to a string containing the descriptive name of that enum. If you have a sparse enum
(one that doesn't start at 0 or has gaps in the numbering) where some of the int
mappings are high enough to make an array-based mapping impractical then you could use a hash table instead.
enum to string in modern C++11 / C++14 / C++17 and future C++20
Magic Enum header-only library provides static reflection for enums (to string, from string, iteration) for C++17.
#include <magic_enum.hpp>
enum Color { RED = 2, BLUE = 4, GREEN = 8 };
Color color = Color::RED;
auto color_name = magic_enum::enum_name(color);
// color_name -> "RED"
std::string color_name{"GREEN"};
auto color = magic_enum::enum_cast<Color>(color_name)
if (color.has_value()) {
// color.value() -> Color::GREEN
};
For more examples check home repository https://github.com/Neargye/magic_enum.
Where is the drawback?
This library uses a compiler-specific hack (based on __PRETTY_FUNCTION__
/ __FUNCSIG__
), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 9.
Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]
.
By default
MAGIC_ENUM_RANGE_MIN = -128
,MAGIC_ENUM_RANGE_MAX = 128
.If need another range for all enum types by default, redefine the macro
MAGIC_ENUM_RANGE_MIN
andMAGIC_ENUM_RANGE_MAX
.MAGIC_ENUM_RANGE_MIN
must be less or equals than0
and must be greater thanINT16_MIN
.MAGIC_ENUM_RANGE_MAX
must be greater than0
and must be less thanINT16_MAX
.If need another range for specific enum type, add specialization enum_range for necessary enum type.
#include <magic_enum.hpp>
enum number { one = 100, two = 200, three = 300 };
namespace magic_enum {
template <>
struct enum_range<number> {
static constexpr int min = 100;
static constexpr int max = 300;
};
}
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 apple
int main() {
printf("%s\n", str(foo));
printf("%s\n", xstr(foo));
}
The output would be:
foo
apple
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.
How can I avoid repeating myself when creating a C++ enum and a dependent data structure?
There is an old pre-processor trick for this:
Gadget.data
DEFINE_GADGET(First)
DEFINE_GADGET(Second)
Gadget.**
#define QUOTE_VAL(X) #X
enum Gadget
{
#define DEFINE_GADGET(X) X,
#include "Gadget.data"
#undef DEFINE_GADGET(X)
};
const char* gadget_debug_names[] = {
#define DEFINE_GADGET(X) QUOTE_VAL(X),
#include "Gadget.data"
#undef DEFINE_GADGET(X)
};
Confusion about C macro expansion in enum
The macros are used for compile time checking. This is useful when you write code that will be compiled and run on many different platforms and where some platforms may not be compatible.
If the first parameter to FWTS_ASSERT
evaluates to non-zero (true) then !!(e)
will evaluate to 1 and the enum will be created with the name FWTS_ASSERT_<second parameter>_in_line_<line>
. I suspect that the enum is never actually used.
If the first parameter to FWTS_ASSERT
evaluates to 0
(= false) then the compiler will try to compute 1/0
and generate a compiler error where it will hopefully tell which enum member caused the error, in this case FWTS_ASSERT_fwts_register_name_to_long_in_line_4
.
And btw, the FWTS_CONCAT_EXPAND(a,b) and FWTS_CONCAT(a, b) seem to be duplicated, why do we need 2 of them?
FTW_CONCAT_EXPAND
is done in 2 steps because we want to first expand any macros in the parameters and then perform the concatenation. Doing it in two steps makes the preprocessor do macro expansion of the parameters before it does the string concatenation.
How to generate compile time enum values with a macro function in c#?
According to @PaulF and similar answer from here.
one possible solution could be:
public sealed class UnixDBCSPages
{
public static readonly uint JIS = MakeUnixDBCS(Convert.ToUInt32(0x0C));
public static readonly uint EUCJP = MakeUnixDBCS(Convert.ToUInt32(0x0D));
public static readonly uint CNS11643_1 = MakeUnixDBCS(3);
public static readonly uint EUC_CNS_1 = MakeUnixDBCS(7) ;
public static readonly uint CNS11643_2 = MakeUnixDBCS(4) ;
public static readonly uint EUC_CNS_2 = MakeUnixDBCS(8);
public static readonly uint KSC1987 = MakeUnixDBCS(6);
public static readonly uint GB2312 = MakeUnixDBCS(5);
private static uint MakeUnixDBCS(uint wCodePage)
{
uint wUnixUnmask = Convert.ToUInt32(Flags.UnixUnmask);
return (wUnixUnmask | wCodePage) << 16;
}
}
Making something both a C identifier and a string?
For your second #define, you need to use the # preprocessor operator, like this:
#define myDefine(a) myFunc(a, #a);
That converts the argument to a string.
Can a C program determine a macro identifier/enum name based on its value?
Not directly, as pointed out by others those identifiers are not available at runtime, but you can use a parallel list of names (an X Macro can help):
#include <stdio.h>
#define ERRS \
X(ERR_SUCCESS) \
X(ERR_BAD_INPUT) \
X(ERR_MORE)
#define X(x) x,
enum err_t {ERRS};
#undef X
#define X(x) #x,
static char *err_name[] = {ERRS};
#undef X
static int foo(void)
{
/* ... */
return ERR_BAD_INPUT;
}
int main(void)
{
printf("%s\n", err_name[foo()]);
return 0;
}
Output:
ERR_BAD_INPUT
Related Topics
C++ Check If Statement Can Be Evaluated Constexpr
Race-Condition in Pthread_Once()
Why Can't I Put a Variable Declaration in the Test Portion of a While Loop
Testing If Given Number Is Integer
C++11 Variadic Printf Performance
Comparing Two Integers Without Any Comparison
Creating a New Object from Dynamic Type Info
Less Verbose Way to Declare Multidimensional Std::Array
Copy a Std::Vector to a Repeated Field from Protobuf with Memcpy
Getting Std::Thread/Mutex to Work Under Win7 with Mingw and G++ 4.7.2
Qt 4.X: How to Implement Drag-And-Drop Onto the Desktop or into a Folder
Is There a Shorter Way to Write Compound 'If' Conditions
How to Convert a String of Hex Values to a String
Memset for Initialization in C++
C++ Cannot Convert from Base a to Derived Type B via Virtual Base A