How can I print enum in C? [duplicate] - c

int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay;
int j = 0;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&j);
TheDay = Days(j);
//how to PRINT THE VALUES stored in TheDay
printf("%s",TheDay); // isnt working
return 0;
}

Enumerations in C are numbers that have convenient names inside your code. They are not strings, and the names assigned to them in the source code are not compiled into your program, and so they are not accessible at runtime.
The only way to get what you want is to write a function yourself that translates the enumeration value into a string. E.g. (assuming here that you move the declaration of enum Days outside of main):
const char* getDayName(enum Days day)
{
switch (day)
{
case Sunday: return "Sunday";
case Monday: return "Monday";
/* etc... */
}
}
/* Then, later in main: */
printf("%s", getDayName(TheDay));
Alternatively, you could use an array as a map, e.g.
const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };
/* ... */
printf("%s", dayNames[TheDay]);
But here you would probably want to assign Sunday = 0 in the enumeration to be safe... I'm not sure if the C standard requires compilers to begin enumerations from 0, although most do (I'm sure someone will comment to confirm or deny this).

I use something like this:
in a file "EnumToString.h":
#undef DECL_ENUM_ELEMENT
#undef DECL_ENUM_ELEMENT_VAL
#undef DECL_ENUM_ELEMENT_STR
#undef DECL_ENUM_ELEMENT_VAL_STR
#undef BEGIN_ENUM
#undef END_ENUM
#ifndef GENERATE_ENUM_STRINGS
#define DECL_ENUM_ELEMENT( element ) element,
#define DECL_ENUM_ELEMENT_VAL( element, value ) element = value,
#define DECL_ENUM_ELEMENT_STR( element, descr ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_VAL( element, value )
#define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
#define END_ENUM( ENUM_NAME ) ENUM_NAME; \
const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
#define BEGIN_ENUM( ENUM_NAME) const char * GetString##ENUM_NAME( enum tag##ENUM_NAME index ) {\
switch( index ) {
#define DECL_ENUM_ELEMENT( element ) case element: return #element; break;
#define DECL_ENUM_ELEMENT_VAL( element, value ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_STR( element, descr ) case element: return descr; break;
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_STR( element, descr )
#define END_ENUM( ENUM_NAME ) default: return "Unknown value"; } } ;
#endif
then in any header file you make the enum declaration, day enum.h
#include "EnumToString.h"
BEGIN_ENUM(Days)
{
DECL_ENUM_ELEMENT(Sunday) //will render "Sunday"
DECL_ENUM_ELEMENT(Monday) //will render "Monday"
DECL_ENUM_ELEMENT_STR(Tuesday, "Tuesday string") //will render "Tuesday string"
DECL_ENUM_ELEMENT(Wednesday) //will render "Wednesday"
DECL_ENUM_ELEMENT_VAL_STR(Thursday, 500, "Thursday string") // will render "Thursday string" and the enum will have 500 as value
/* ... and so on */
}
END_ENUM(MyEnum)
then in a file called EnumToString.c:
#include "enum.h"
#define GENERATE_ENUM_STRINGS // Start string generation
#include "enum.h"
#undef GENERATE_ENUM_STRINGS // Stop string generation
then in main.c:
int main(int argc, char* argv[])
{
Days TheDay = Monday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "1 - Monday"
TheDay = Thursday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "500 - Thursday string"
return 0;
}
this will generate "automatically" the strings for any enums declared this way and included in "EnumToString.c"

The way I usually do this is by storing the string representations in a separate array in the same order, then indexing the array with the enum value:
const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"

enums in C don't really work the way you're expecting them to. You can think of them kind of like glorified constants (with a few additional benefits relating to being a collection of such constants), and the text you've written in for "Sunday" really gets resolved to a number during compilation, the text is ultimately discarded.
In short: to do what you really want you'll need to keep an array of the strings or create a function to map from the enum's value to the text you'd like to print.

Enumerations in C are basically syntactical sugar for named lists of automatically-sequenced integer values. That is, when you have this code:
int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay = Monday;
}
Your compiler actually spits out this:
int main()
{
int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}
Therefore, outputting a C enumeration as a string is not an operation that makes sense to the compiler. If you want to have human-readable strings for these, you will need to define functions to convert from enumerations to strings.

Here's a cleaner way to do it with macros:
#include <stdio.h>
#include <stdlib.h>
#define DOW(X, S) \
X(Sunday) S X(Monday) S X(Tuesday) S X(Wednesday) S X(Thursday) S X(Friday) S X(Saturday)
#define COMMA ,
/* declare the enum */
#define DOW_ENUM(DOW) DOW
enum dow {
DOW(DOW_ENUM, COMMA)
};
/* create an array of strings with the enum names... */
#define DOW_ARR(DOW ) [DOW] = #DOW
const char * const dow_str[] = {
DOW(DOW_ARR, COMMA)
};
/* ...or create a switchy function. */
static const char * dowstr(int i)
{
#define DOW_CASE(D) case D: return #D
switch(i) {
DOW(DOW_CASE, ;);
default: return NULL;
}
}
int main(void)
{
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dow_str[i]);
printf("\n");
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dowstr(i));
return 0;
}
I'm not sure that this is totally portable b/w preprocessors, but it works with gcc.
This is c99 btw, so use c99 strict if you plug it into (the online compiler) ideone.

I know I am late to the party, but how about this?
const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ };
printf("%s", dayNames[Sunday]); // prints "Sunday"
This way, you do not have to manually keep the enum and the char* array in sync. If you are like me, chances are that you will later change the enum, and the char* array will print invalid strings.
This may not be a feature universally supported. But afaik, most of the mordern day C compilers support this designated initialier style.
You can read more about designated initializers here.

I like this to have enum in the dayNames.
To reduce typing, we can do the following:
#define EP(x) [x] = #x /* ENUM PRINT */
const char* dayNames[] = { EP(Sunday), EP(Monday)};

The question is you want write the name just one times.
I have an ider like this:
#define __ENUM(situation,num) \
int situation = num; const char * __##situation##_name = #situation;
const struct {
__ENUM(get_other_string, -203);//using a __ENUM Mirco make it ease to write,
__ENUM(get_negative_to_unsigned, -204);
__ENUM(overflow,-205);
//The following two line showing the expanding for __ENUM
int get_no_num = -201; const char * __get_no_num_name = "get_no_num";
int get_float_to_int = -202; const char * get_float_to_int_name = "float_to_int_name";
}eRevJson;
#undef __ENUM
struct sIntCharPtr { int value; const char * p_name; };
//This function transform it to string.
inline const char * enumRevJsonGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eRevJson);
for (int i = 0;i < sizeof(eRevJson) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
it uses a struct to insert enum, so that a printer to string could follows each enum value define.
int main(int argc, char *argv[]) {
int enum_test = eRevJson.get_other_string;
printf("error is %s, number is %d\n", enumRevJsonGetString(enum_test), enum_test);
>error is get_other_string, number is -203
The difference to enum is builder can not report error if the numbers are repeated.
if you don't like write number, __LINE__ could replace it:
#define ____LINE__ __LINE__
#define __ENUM(situation) \
int situation = (____LINE__ - __BASELINE -2); const char * __##situation##_name = #situation;
constexpr int __BASELINE = __LINE__;
constexpr struct {
__ENUM(Sunday);
__ENUM(Monday);
__ENUM(Tuesday);
__ENUM(Wednesday);
__ENUM(Thursday);
__ENUM(Friday);
__ENUM(Saturday);
}eDays;
#undef __ENUM
inline const char * enumDaysGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eDays);
for (int i = 0;i < sizeof(eDays) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
int main(int argc, char *argv[]) {
int d = eDays.Wednesday;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
d = 1;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
}
>day Wednesday, number is 3 >day Monday, number is 1

There is another solution: Create your own dynamic enumeration class. Means you have a struct and some function to create a new enumeration, which stores the elements in a struct and each element has a string for the name. You also need some type to store a individual elements, functions to compare them and so on.
Here is an example:
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Enumeration_element_T
{
size_t index;
struct Enumeration_T *parent;
char *name;
};
struct Enumeration_T
{
size_t len;
struct Enumeration_element_T elements[];
};
void enumeration_delete(struct Enumeration_T *self)
{
if(self)
{
while(self->len--)
{
free(self->elements[self->len].name);
}
free(self);
}
}
struct Enumeration_T *enumeration_create(size_t len,...)
{
//We do not check for size_t overflows, but we should.
struct Enumeration_T *self=malloc(sizeof(self)+sizeof(self->elements[0])*len);
if(!self)
{
return NULL;
}
self->len=0;
va_list l;
va_start(l,len);
for(size_t i=0;i<len;i++)
{
const char *name=va_arg(l,const char *);
self->elements[i].name=malloc(strlen(name)+1);
if(!self->elements[i].name)
{
enumeration_delete(self);
return NULL;
}
strcpy(self->elements[i].name,name);
self->len++;
}
return self;
}
bool enumeration_isEqual(struct Enumeration_element_T *a,struct Enumeration_element_T *b)
{
return a->parent==b->parent && a->index==b->index;
}
bool enumeration_isName(struct Enumeration_element_T *a, const char *name)
{
return !strcmp(a->name,name);
}
const char *enumeration_getName(struct Enumeration_element_T *a)
{
return a->name;
}
struct Enumeration_element_T *enumeration_getFromName(struct Enumeration_T *self, const char *name)
{
for(size_t i=0;i<self->len;i++)
{
if(enumeration_isName(&self->elements[i],name))
{
return &self->elements[i];
}
}
return NULL;
}
struct Enumeration_element_T *enumeration_get(struct Enumeration_T *self, size_t index)
{
return &self->elements[index];
}
size_t enumeration_getCount(struct Enumeration_T *self)
{
return self->len;
}
bool enumeration_isInRange(struct Enumeration_T *self, size_t index)
{
return index<self->len;
}
int main(void)
{
struct Enumeration_T *weekdays=enumeration_create(7,"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
if(!weekdays)
{
return 1;
}
printf("Please enter the day of the week (0 to 6)\n");
size_t j = 0;
if(scanf("%zu",&j)!=1)
{
enumeration_delete(weekdays);
return 1;
}
// j=j%enumeration_getCount(weekdays); //alternative way to make sure j is in range
if(!enumeration_isInRange(weekdays,j))
{
enumeration_delete(weekdays);
return 1;
}
struct Enumeration_element_T *day=enumeration_get(weekdays,j);
printf("%s\n",enumeration_getName(day));
enumeration_delete(weekdays);
return 0;
}
The functions of enumeration should be in their own translation unit, but i combined them here to make it simpler.
The advantage is that this solution is flexible, follows the DRY principle, you can store information along with each element, you can create new enumerations during runtime and you can add new elements during runtime.
The disadvantage is that this is complex, needs dynamic memory allocation, can't be used in switch-case, needs more memory and is slower. The question is if you should not use a higher level language in cases where you need this.

Using a Macro and stringize operator(#) we can achieve this....
#include <stdio.h>
typedef enum
{
MON=0,
TUE
}week;
int main()
{
#define printt(data) printf("%s",#data);
printt(MON);
return 0;
}

i'm new to this but a switch statement will defenitely work
#include <stdio.h>
enum mycolor;
int main(int argc, const char * argv[])
{
enum Days{Sunday=1,Monday=2,Tuesday=3,Wednesday=4,Thursday=5,Friday=6,Saturday=7};
enum Days TheDay;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&TheDay);
switch (TheDay)
{
case Sunday:
printf("the selected day is sunday");
break;
case Monday:
printf("the selected day is monday");
break;
case Tuesday:
printf("the selected day is Tuesday");
break;
case Wednesday:
printf("the selected day is Wednesday");
break;
case Thursday:
printf("the selected day is thursday");
break;
case Friday:
printf("the selected day is friday");
break;
case Saturday:
printf("the selected day is Saturaday");
break;
default:
break;
}
return 0;
}

TheDay maps back to some integer type. So:
printf("%s", TheDay);
Attempts to parse TheDay as a string, and will either print out garbage or crash.
printf is not typesafe and trusts you to pass the right value to it. To print out the name of the value, you'd need to create some method for mapping the enum value to a string - either a lookup table, giant switch statement, etc.

Related

Good way to have an enum string value

I find myself doing the following pattern quite a bit in C:
enum type {String, Number, Unknown};
const char* get_token_type(int type) {
switch (type) {
case String: return "String";
case Number: return "Number";
default: return "Unknown";
}
}
Are there any nice alternatives where I can sort of wrap the two up in one?
Here's one more way, it uses a global and not sure how 'clean' it is but at least I can set up everything up at the top in one copy-paste job.
enum type {String, Number, Unknown};
char type_string[][40] = {"String", "Number","Unknown"};
const char* get_token_type(int type) {
return type_string[type];
}
The ugly and slow switch solution should be replaced by a readable a look-up table:
const char* const type_string[] = {"String", "Number","Unknown"};
typedef enum {String, Number, Unknown, type_size} type;
...
type something = ...;
if(something > 0 && something<type_size)
puts( type_string[something] );
A less recommended but possible solution is "X macros". They are hard to read and mostly used when you have no option to change a program that you are maintaining, in order to centralize all data to a single place in the program.
It would look like this:
#include <stdio.h>
#define TYPE_LIST(X) \
X(String) \
X(Number) \
X(Unknown) \
typedef enum
{
#define X(x) x,
TYPE_LIST(X)
#undef X
type_size
} type;
const char* const type_string[] =
{
#define X(x) [x] = #x, // array designated initializer using enum constant as index
TYPE_LIST(X)
#undef X
};
_Static_assert(sizeof type_string/sizeof *type_string == type_size,
"type and type_string mismatch");
int main (void)
{
printf("%d %d %d\n", String, Number, Unknown);
printf("%s %s %s\n", type_string[String],
type_string[Number],
type_string[Unknown]);
// or if you really like X macros...
#define X(x) printf("%d is %s\n", x, #x);
TYPE_LIST(X)
#undef X
}
(This only works in standard C, not C90, due to the trailing comma in enum language defect in C90)
Here is a set of macros you can use to access and enumerate the enumeration names and/or values:
#include <stdio.h>
#include <string.h>
#define ENUM_DEF(e, ...) e __VA_ARGS__,
#define ENUM_VAL(e, ...) e,
#define ENUM_STR(e, ...) #e,
#define ENUM_CASE(e, ...) case e: return #e;
#define ENUM_COUNT(e, ...) +1
/* this macro contains the names and values of the enumeration members */
#define type_ENUMERATE(V) V(String,) V(Number, = 2) V(Unknown,)
/* the actual enum type definition */
enum type { type_ENUMERATE(ENUM_DEF) };
/* array type_value contains the values in the enumeration */
enum type type_value[] = { type_ENUMERATE(ENUM_VAL) };
/* array type_value contains the names of the enumeration members */
const char *type_name[] = { type_ENUMERATE(ENUM_STR) };
/* type_count is the number of elements in the enumeration */
#define type_count (ENUM_COUNT(e, ...))
const char *get_token_type(int type) {
switch (type) {
/* can only use a switch if all enumeration values are distinct */
type_ENUMERATE(ENUM_CASE);
default:
return "Error";
}
}
int main() {
printf("The type names and values are:\n");
/* format %d might be inappropriate if the enumeration values are too large */
for (int i = 0; i < type_count; i++) {
printf(" %s: %d\n", type_name[i], type_value[i]);
}
printf("String: %s -> %d\n", get_token_type(String), String);
printf("Number: %s -> %d\n", get_token_type(Number), Number);
printf("Unknown: %s -> %d\n", get_token_type(Unknown), Unknown);
printf("-1: %s -> %d\n", get_token_type(-1), -1);
return 0;
}
This works only for enums which are continously enumerated. If you have enums like V1 = 2, V2 = 5, ... it will not work, or you would have to manullay count them.
In this case you will get a compiletime error when you add or remove an enum, and you forgot to add/remove the name string. If you rename an enum you will get also an error, because the previous name no longer exits.
#include <stdio.h>
#include <string.h>
#define xstr(s) TOSTRING(s)
#define TOSTRING(s) #s
typedef enum
{
VALUE1
,VALUE2
,VALUE3
,VALUE_MAX
} Values;
typedef struct namemap
{
const char *name;
Values enumValue;
} NameMap;
const NameMap valueNames[] =
{
{ TOSTRING(VALUE1), __COUNTER__ }
, { TOSTRING(VALUE2), __COUNTER__ }
, { TOSTRING(VALUE3), __COUNTER__ }
};
static_assert((__COUNTER__) == VALUE_MAX, "Name missing in enum name array");
int main()
{
printf("%s\n", valueNames[VALUE1].name);
return 0;
}

can we use switch-case statement with strings in c? [duplicate]

This question already has answers here:
How can I compare strings in C using a `switch` statement?
(16 answers)
Closed 5 years ago.
int a = 0 , b = 0;
char* c = NULL;
int main(int argc , char ** argv){
c = argv[2];
a = atoi(argv[1]);
b = atoi(argv[3]);
switch(c){
case "+": printf(a+b);
break;
}
printf("\n\n");
return 0;
}
No, you can't. Switch is intended to compare numeric types, and for extension char types.
Instead you should use the strcmp function, included in string header:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
if (argc != 4) {
puts("Incorrect usage");
return 1;
}
/* You should check the number of arguments */
char * op = argv[1];
int a = atoi(argv[2]);
int b = atoi(argv[3]);
/* You should check correct input too */
if (strcmp(op, "+") == 0)
printf("%d + %d = %d\n", a, b, a + b);
else if (strcmp(op, "-") == 0)
printf("%d - %d = %d\n", a, b, a - b);
/* Add more functions here */
return 0;
}
No you can't. The case labels of a switch need to be compile time evaluable constant expressions with an integral type.
But int literals like '+' satisfy that requirement. (As do enum values for that matter.)
Some folk like to use implementation-defined multi-character literals (e.g. 'eax') as case labels as they claim it helps readability, but at that point, you're giving up consistent behaviour across different platforms.
If you need to branch on the value of a NUL-terminated char array, then use an if block.
There are two cases to the answer ..
Firstly 6.8.4.2 (switch case)
The controlling expression of a switch statement shall have integer
type
Secondly 6.8.4.2 (the case statements)
The expression of each case label shall be an integer constant
expression and no two of the case constant expressions in the same
switch statement shall have the same value after conversion
Long story short - you can't use string literal like that. Neither in switch controlling expression nor in case.
You can do the string comparisons using strcmp and then do the if-else conditioning. The context on which you ask this, you can simply pass the character + (argv[2][0]) instead of passing the whole literal. That way you will be passing char to the switch expression and then work accordingly.
Nope, that's not possible.
Quoting C11, chapter §6.8.4.2
The controlling expression of a switch statement shall have integer type.
in your case, you don't seem to need a string but rather the first (and only character) of the string passed in the switch statement, in that case that's possible using character literal (which has integer type) in the case statements:
if (strlen(c)==1)
{
switch(c[0]){
case '+': printf(a+b);
break;
...
}
}
some good other alternatives are described in best way to switch on a string in C when the string has multiple characters.
Not directly. But yes, you can.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// The way you store and search for names is entirely
// up to you. This is a simple linear search of an
// array. If you have a lot of names, you might choose
// a better storage + lookup, such as a hash table.
int find( const char** ss, int n, const char* s )
{
int i = 0;
while (i < n)
if (strcmp( ss[i], s ) == 0) break;
else i += 1;
return i;
}
// A bevvy of little utilities to help out.
char* strupper( char* s )
{
char* p = s;
while ((*p = toupper( *p ))) ++p;
return s;
}
char* zero( char* p ) { if (p) *p = 0; return p; }
#define STRINGIFY(S) STRINGIFY0(S)
#define STRINGIFY0(S) #S
int main()
{
// Our list of names are enumerated constants with associated
// string data. We use the Enum Macro Trick for succinct ODR happiness.
#define NAMES(F) \
F(MARINETTE) \
F(ADRIAN) \
F(ALYA) \
F(DINO)
#define ENUM_F(NAME) NAME,
#define STRING_F(NAME) STRINGIFY(NAME),
enum names { NAMES(ENUM_F) NUM_NAMES };
const char* names[ NUM_NAMES ] = { NAMES(STRING_F) NULL };
#undef STRING_F
#undef ENUM_F
#undef NAMES
// Ask user for a name
char s[ 500 ];
printf( "name? " );
fflush( stdout );
fgets( s, sizeof( s ), stdin );
zero( strchr( s, '\n' ) );
// Preprocess and search for the name
switch (find( names, sizeof(names)/sizeof(*names), strupper( s ) ))
{
case MARINETTE: puts( "Ladybug!" ); break;
case ADRIAN: puts( "Chat Noir!" ); break;
case ALYA:
case DINO: puts( "Best friend!" ); break;
default: puts( "Who?" );
}
}
Keep in mind this works by pure, unadulterated magic tricks, and is not suitable for large collections of text values.
Also, the validity of the match is entirely dependent on the degree to which you pre-process the user’s input. In this example we only ignore case, but a more advanced application might perform some more sophisticated matching.
As others pointed out in C one cannot use a string as argument to a switch, nor to its case-labels.
To get around this limitation one could map each string to a specific integer and pass this to the switch.
Looking up the mapping requires searching the map, which can be done using the Standard C bsearch() function.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int cmp(const void * pv1, const void * pv2)
{
const struct Operation_Descriptor * pop1 = pv1;
const struct Operation_Descriptor * pop2 = pv2;
return strcmp(pop1->name, pop2->name);
}
int main(int argc, char ** argv)
{
size_t s = sizeof operations / sizeof *operations;
/* bsearch() requires the array to search to be sorted. */
qsort(operations, s, sizeof *operations, cmp);
{
struct Operation_Descriptor * pop =
bsearch(
&(struct Operation_Descriptor){argv[1], OP_INVALID},
operations, s, sizeof *operations, cmp);
switch(pop ?pop->op :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
}
If on POSIX one can even use a hash table, which is the fastest way to lookup the mapping.
An example might look like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <search.h>
enum Operation {
OP_INVALID = -1,
OP_ADD,
OP_SUBTRACT,
OP_MULTIPLY,
OP_DIVIDE,
OP_MAX
};
struct Operation_Descriptor {
char * name;
enum Operation op;
};
struct Operation_Descriptor operations [] = {
{"add", OP_ADD},
{"subtract", OP_SUBTRACT},
{"multiply", OP_MULTIPLY},
{"divide", OP_DIVIDE}
};
int main(int argc, char ** argv)
{
if (0 == hcreate(5))
{
perror("hcreate() failed");
exit(EXIT_FAILURE);
}
for (size_t i = 0; i < s; ++i)
{
if (!hsearch((ENTRY){operations[i].name, &operations[i].op}, ENTER))
{
perror("hsearch(ENTER) failed");
exit(EXIT_FAILURE);
}
}
{
ENTRY * ep = hsearch((ENTRY){argv[1], NULL}, FIND);
switch(ep ?*((enum Operation *)ep->data) :OP_INVALID)
{
case OP_ADD:
/* Code to add goes here, */
break;
case OP_SUBTRACT:
/* Code to subtract goes here, */
break;
case OP_MULTIPLY:
/* Code to multiply goes here, */
break;
case OP_DIVIDE:
/* Code to divide goes here, */
break;
case OP_INVALID:
default:
fprintf(stderr, "unhandled or invalid operation '%s'\n", argv[1]);
break;
}
}
hdestroy(); /* Clean up. */
}

How to protect enum assignment

I want to prevent invalid value enum assignment. I know if i even assign value that is not in enum it will work. Example:
enum example_enum
{
ENUM_VAL0,
ENUM_VAL1,
ENUM_VAL2,
ENUM_VAL3
};
void example_function(void)
{
enum example_enum the_enum = ENUM_VAL3; // correct
the_enum = 41; // will work
the_enum = 0xBADA55; // also will work
bar(the_enum); // this function assumes that input parameter is correct
}
Is there easy, efficient way to check if assignment to enum is correct? I could test value by function
void foo(enum example_enum the_enum)
{
if (!is_enum(the_enum))
return;
// do something with valid enum
}
I could resolve this in following way:
static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3 };
int is_enum(int input)
{
for (int i=0;i<4;i++)
if (e_values[i] == input)
return 1;
return 0;
}
For me, my solution is inefficient, how can i write this if i have more enums and more values in enums?
As long as the enum is continuous one can do something like this:
static int e_values[] = { ENUM_VAL0, ENUM_VAL1, ENUM_VAL2, ENUM_VAL3, ENUM_VAL_COUNT };
int is_enum(int input) { return 0 <= input && input < ENUM_VAL_COUNT; }
Another alternative is to not validate the enum value beforehand, but error out once the code detects an invalid value:
switch(input) {
case ENUM_VAL0: ... break;
case ENUM_VAL1: ... break;
...
default:
assert(0 && "broken enum");
break;
}
But there is no way to enforce that the enum value doesn't go out of the range at all in C. The best you can do if you want to secure the enum against fiddling is to hide the value away in a struct and then have functions to manipulate the struct. The function and struct implementation can be hidden away from the user via a forward declaration in the .h file and the implementation in the .c file:
struct example_t {
enum example_enum value;
}
void example_set_val0(example_t* v) { v->value = ENUM_VAL0; }
There is no way of warning about assigning integers that fit into the enum.
Enumerators in C are synonyms for integer types. Assuming the type chosen for enum example_enum is int, then your code is identical to:
void example_function(void)
{
int the_enum = ENUM_VAL3; // correct
the_enum = 12345; // will work
bar(the_enum); // this function assumes that input parameter is correct
}
void foo(int the_enum)
{
if (!is_enum(the_enum))
return;
// do something with valid enum
}
You could use structures, but even that can be circumvented:
struct example_enum_struct e = { 12345 };
e.value = 23456;
Basically if you want to restrict a type to specific values, you will need to perform checks.
If anyone is interested in this topic, here I have some solution which works.
typed_enums.h
#ifndef TYPED_ENUMS_H
#define TYPED_ENUMS_H
#define TYPED_ENUM(name_) \
typedef struct { int v; } name_
#define TYPED_ENUM_VALUE(name_, value_) (name_) { value_ }
#define GET_TYPED_ENUM_VALUE(en_) (en_.v)
#define TYPED_ENUM_EQ(a_, b_) (GET_TYPED_ENUM_VALUE(a_) == GET_TYPED_ENUM_VALUE(b_))
#endif
usb_class.h
#ifndef USB_CLASS_H
#define USB_CLASS_H
#include "typed_enums.h"
TYPED_ENUM(UsbClass);
#define USB_CLASS_BILLBOARD TYPED_ENUM_VALUE(UsbClass, 0x11)
#define USB_CLASS_TYPE_C_BRIDGE TYPED_ENUM_VALUE(UsbClass, 0x12)
#define USB_CLASS_DIAGNOSTIC_DEVICE TYPED_ENUM_VALUE(UsbClass, 0xDC)
#define USB_CLASS_WIRELESS_CONTROLLER TYPED_ENUM_VALUE(UsbClass, 0xE0)
#endif
usb_class_example.c
#include "typed_enums.h"
#include "usb_class.h"
#include <stdio.h>
int main(int argc, char ** argv)
{
UsbClass usbClass = USB_CLASS_WIRELESS_CONTROLLER;
usbClass = 12345; // tadam!!!! throws error
usbClass = USB_CLASS_VIDEO;
if (TYPED_ENUM_EQ(usbClass, USB_CLASS_VIDEO)) {
printf("usbClass = USB_CLASS_VIDEO\n");
}
printf("usb class value: %02X\n", GET_TYPED_ENUM_VALUE(usbClass));
return 0;
}
Pros:
enum value assignment works like struct assignment
enum for pointers also works
enum value can't be changed
Cons:
can't be used in switch
can't be directly compared
can't directly return enum number value
Note: sorry for abusing preprocessor here

how to best achieve string to number mapping in a c program

I have a definite set of strings and its corresponding numbers:
kill -> 1
live -> 2
half_kill -> 3
dont_live -> 4
List is of 30 such strings and their number mapping.
If user enters "kill", I need to return 1 and if he enters "dont_live" I need to return 4.
How should I achieve this in c program? I am looking for an efficient solution because this operation needs to be done 100s of times.
should I put them in #define in my .h file?
Thanks in advance.
Sort your table, and use the standard library function bsearch to perform a binary search.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct entry {
char *str;
int n;
};
/* sorted according to str */
struct entry dict[] = {
"dont_live", 4,
"half_kill", 3,
"kill", 1,
"live", 2,
};
int compare(const void *s1, const void *s2)
{
const struct entry *e1 = s1;
const struct entry *e2 = s2;
return strcmp(e1->str, e2->str);
}
int
main (int argc, char *argv[])
{
struct entry *result, key = {argv[1]};
result = bsearch(&key, dict, sizeof(dict)/sizeof(dict[0]),
sizeof dict[0], compare);
if (result)
printf("%d\n", result->n);
return 0;
}
Here's what you get when you run the program.
$ ./a.out kill
1
$ ./a.out half_kill
3
$ ./a.out foo
<no output>
PS: I reused portions of sidyll's program. My answer should now be CC BY-SA compliant :p
A possible solution:
#include <stdio.h>
#include <string.h>
struct entry {
char *str;
int n;
};
struct entry dict[] = {
"kill", 1,
"live", 2,
"half_kill", 3,
"dont_live", 4,
0,0
};
int
number_for_key(char *key)
{
int i = 0;
char *name = dict[i].str;
while (name) {
if (strcmp(name, key) == 0)
return dict[i].n;
name = dict[++i].str;
}
return 0;
}
int
main (int argc, char *argv[])
{
printf("enter your keyword: ");
char s[100]; scanf("%s", s);
printf("the number is: %d\n", number_for_key(s));
return 0;
}
Here's one approach:
int get_index(char *s)
{
static const char mapping[] = "\1.kill\2.live\3.half_kill\4.dont_live";
char buf[sizeof mapping];
const char *p;
snprintf(buf, sizeof buf, ".%s", s);
p = strstr(mapping, buf);
return p ? p[-1] : 0;
}
The . mess is to work around kill being a substring of half_kill. Without that issue you could simply search for the string directly.
If it is a very short list of strings then a simple block of ifs will be more than sufficient
if (0 == strcmp(value, "kill")) {
return 1;
}
if (0 == strcmp(value, "live")) {
return 2;
}
...
If the number approach 10 I would begin to profile my application though and consider a map style structure.
if you have a fixed set of strimgs, you have two options: generate a perfect hashing function (check gperf or cmph) or create a trie so that you never have to check charcters more than once.
Compilers usually use perfect hashes to recognize a language keyword, in your case I would probably go with the trie, it should be the fastest way (but nothing beats direct measurement!)
Is it really a bottleneck? You should worry about efficiency only if the simple solution proves to be too slow.
Having said that, possible speed improvements are checking the lengths first:
If it's 4 characters then it could be "kill" or "live"
If it's 9 characters then it could be "half_kill" or "dont_live"
or checking the first character in a switch statement:
switch (string[0]) {
case 'k':
if (strcmp(string, "kill") == 0)
return 1;
return 0;
case 'l':
...
default:
return 0;
}
Use hashmap/ hashtable i think this would be the best solution.
Can you use an Enumunerator?
int main(void) {
enum outcome { kill=1, live, half_kill, dont_live };
printf("%i\n", kill); //1
printf("%i\n", dont_live); //4
printf("%i\n", half_kill); //3
printf("%i\n", live); //2
return 0;
}
Create a list of const values:
const int kill = 1;
const int live = 2;
const int half_kill = 3;
etc

Print text instead of value from C enum

int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay;
int j = 0;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&j);
TheDay = Days(j);
//how to PRINT THE VALUES stored in TheDay
printf("%s",TheDay); // isnt working
return 0;
}
Enumerations in C are numbers that have convenient names inside your code. They are not strings, and the names assigned to them in the source code are not compiled into your program, and so they are not accessible at runtime.
The only way to get what you want is to write a function yourself that translates the enumeration value into a string. E.g. (assuming here that you move the declaration of enum Days outside of main):
const char* getDayName(enum Days day)
{
switch (day)
{
case Sunday: return "Sunday";
case Monday: return "Monday";
/* etc... */
}
}
/* Then, later in main: */
printf("%s", getDayName(TheDay));
Alternatively, you could use an array as a map, e.g.
const char* dayNames[] = {"Sunday", "Monday", "Tuesday", /* ... etc ... */ };
/* ... */
printf("%s", dayNames[TheDay]);
But here you would probably want to assign Sunday = 0 in the enumeration to be safe... I'm not sure if the C standard requires compilers to begin enumerations from 0, although most do (I'm sure someone will comment to confirm or deny this).
I use something like this:
in a file "EnumToString.h":
#undef DECL_ENUM_ELEMENT
#undef DECL_ENUM_ELEMENT_VAL
#undef DECL_ENUM_ELEMENT_STR
#undef DECL_ENUM_ELEMENT_VAL_STR
#undef BEGIN_ENUM
#undef END_ENUM
#ifndef GENERATE_ENUM_STRINGS
#define DECL_ENUM_ELEMENT( element ) element,
#define DECL_ENUM_ELEMENT_VAL( element, value ) element = value,
#define DECL_ENUM_ELEMENT_STR( element, descr ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_VAL( element, value )
#define BEGIN_ENUM( ENUM_NAME ) typedef enum tag##ENUM_NAME
#define END_ENUM( ENUM_NAME ) ENUM_NAME; \
const char* GetString##ENUM_NAME(enum tag##ENUM_NAME index);
#else
#define BEGIN_ENUM( ENUM_NAME) const char * GetString##ENUM_NAME( enum tag##ENUM_NAME index ) {\
switch( index ) {
#define DECL_ENUM_ELEMENT( element ) case element: return #element; break;
#define DECL_ENUM_ELEMENT_VAL( element, value ) DECL_ENUM_ELEMENT( element )
#define DECL_ENUM_ELEMENT_STR( element, descr ) case element: return descr; break;
#define DECL_ENUM_ELEMENT_VAL_STR( element, value, descr ) DECL_ENUM_ELEMENT_STR( element, descr )
#define END_ENUM( ENUM_NAME ) default: return "Unknown value"; } } ;
#endif
then in any header file you make the enum declaration, day enum.h
#include "EnumToString.h"
BEGIN_ENUM(Days)
{
DECL_ENUM_ELEMENT(Sunday) //will render "Sunday"
DECL_ENUM_ELEMENT(Monday) //will render "Monday"
DECL_ENUM_ELEMENT_STR(Tuesday, "Tuesday string") //will render "Tuesday string"
DECL_ENUM_ELEMENT(Wednesday) //will render "Wednesday"
DECL_ENUM_ELEMENT_VAL_STR(Thursday, 500, "Thursday string") // will render "Thursday string" and the enum will have 500 as value
/* ... and so on */
}
END_ENUM(MyEnum)
then in a file called EnumToString.c:
#include "enum.h"
#define GENERATE_ENUM_STRINGS // Start string generation
#include "enum.h"
#undef GENERATE_ENUM_STRINGS // Stop string generation
then in main.c:
int main(int argc, char* argv[])
{
Days TheDay = Monday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "1 - Monday"
TheDay = Thursday;
printf( "%d - %s\n", TheDay, GetStringDay(TheDay) ); //will print "500 - Thursday string"
return 0;
}
this will generate "automatically" the strings for any enums declared this way and included in "EnumToString.c"
The way I usually do this is by storing the string representations in a separate array in the same order, then indexing the array with the enum value:
const char *DayNames[] = { "Sunday", "Monday", "Tuesday", /* etc */ };
printf("%s", DayNames[Sunday]); // prints "Sunday"
enums in C don't really work the way you're expecting them to. You can think of them kind of like glorified constants (with a few additional benefits relating to being a collection of such constants), and the text you've written in for "Sunday" really gets resolved to a number during compilation, the text is ultimately discarded.
In short: to do what you really want you'll need to keep an array of the strings or create a function to map from the enum's value to the text you'd like to print.
Enumerations in C are basically syntactical sugar for named lists of automatically-sequenced integer values. That is, when you have this code:
int main()
{
enum Days{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday};
Days TheDay = Monday;
}
Your compiler actually spits out this:
int main()
{
int TheDay = 1; // Monday is the second enumeration, hence 1. Sunday would be 0.
}
Therefore, outputting a C enumeration as a string is not an operation that makes sense to the compiler. If you want to have human-readable strings for these, you will need to define functions to convert from enumerations to strings.
Here's a cleaner way to do it with macros:
#include <stdio.h>
#include <stdlib.h>
#define DOW(X, S) \
X(Sunday) S X(Monday) S X(Tuesday) S X(Wednesday) S X(Thursday) S X(Friday) S X(Saturday)
#define COMMA ,
/* declare the enum */
#define DOW_ENUM(DOW) DOW
enum dow {
DOW(DOW_ENUM, COMMA)
};
/* create an array of strings with the enum names... */
#define DOW_ARR(DOW ) [DOW] = #DOW
const char * const dow_str[] = {
DOW(DOW_ARR, COMMA)
};
/* ...or create a switchy function. */
static const char * dowstr(int i)
{
#define DOW_CASE(D) case D: return #D
switch(i) {
DOW(DOW_CASE, ;);
default: return NULL;
}
}
int main(void)
{
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dow_str[i]);
printf("\n");
for(int i = 0; i < 7; i++)
printf("[%d] = «%s»\n", i, dowstr(i));
return 0;
}
I'm not sure that this is totally portable b/w preprocessors, but it works with gcc.
This is c99 btw, so use c99 strict if you plug it into (the online compiler) ideone.
I know I am late to the party, but how about this?
const char* dayNames[] = { [Sunday] = "Sunday", [Monday] = "Monday", /*and so on*/ };
printf("%s", dayNames[Sunday]); // prints "Sunday"
This way, you do not have to manually keep the enum and the char* array in sync. If you are like me, chances are that you will later change the enum, and the char* array will print invalid strings.
This may not be a feature universally supported. But afaik, most of the mordern day C compilers support this designated initialier style.
You can read more about designated initializers here.
I like this to have enum in the dayNames.
To reduce typing, we can do the following:
#define EP(x) [x] = #x /* ENUM PRINT */
const char* dayNames[] = { EP(Sunday), EP(Monday)};
The question is you want write the name just one times.
I have an ider like this:
#define __ENUM(situation,num) \
int situation = num; const char * __##situation##_name = #situation;
const struct {
__ENUM(get_other_string, -203);//using a __ENUM Mirco make it ease to write,
__ENUM(get_negative_to_unsigned, -204);
__ENUM(overflow,-205);
//The following two line showing the expanding for __ENUM
int get_no_num = -201; const char * __get_no_num_name = "get_no_num";
int get_float_to_int = -202; const char * get_float_to_int_name = "float_to_int_name";
}eRevJson;
#undef __ENUM
struct sIntCharPtr { int value; const char * p_name; };
//This function transform it to string.
inline const char * enumRevJsonGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eRevJson);
for (int i = 0;i < sizeof(eRevJson) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
it uses a struct to insert enum, so that a printer to string could follows each enum value define.
int main(int argc, char *argv[]) {
int enum_test = eRevJson.get_other_string;
printf("error is %s, number is %d\n", enumRevJsonGetString(enum_test), enum_test);
>error is get_other_string, number is -203
The difference to enum is builder can not report error if the numbers are repeated.
if you don't like write number, __LINE__ could replace it:
#define ____LINE__ __LINE__
#define __ENUM(situation) \
int situation = (____LINE__ - __BASELINE -2); const char * __##situation##_name = #situation;
constexpr int __BASELINE = __LINE__;
constexpr struct {
__ENUM(Sunday);
__ENUM(Monday);
__ENUM(Tuesday);
__ENUM(Wednesday);
__ENUM(Thursday);
__ENUM(Friday);
__ENUM(Saturday);
}eDays;
#undef __ENUM
inline const char * enumDaysGetString(int num) {
sIntCharPtr * ptr = (sIntCharPtr *)(&eDays);
for (int i = 0;i < sizeof(eDays) / sizeof(sIntCharPtr);i++) {
if (ptr[i].value == num) {
return ptr[i].p_name;
}
}
return "bad_enum_value";
}
int main(int argc, char *argv[]) {
int d = eDays.Wednesday;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
d = 1;
printf("day %s, number is %d\n", enumDaysGetString(d), d);
}
>day Wednesday, number is 3 >day Monday, number is 1
There is another solution: Create your own dynamic enumeration class. Means you have a struct and some function to create a new enumeration, which stores the elements in a struct and each element has a string for the name. You also need some type to store a individual elements, functions to compare them and so on.
Here is an example:
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Enumeration_element_T
{
size_t index;
struct Enumeration_T *parent;
char *name;
};
struct Enumeration_T
{
size_t len;
struct Enumeration_element_T elements[];
};
void enumeration_delete(struct Enumeration_T *self)
{
if(self)
{
while(self->len--)
{
free(self->elements[self->len].name);
}
free(self);
}
}
struct Enumeration_T *enumeration_create(size_t len,...)
{
//We do not check for size_t overflows, but we should.
struct Enumeration_T *self=malloc(sizeof(self)+sizeof(self->elements[0])*len);
if(!self)
{
return NULL;
}
self->len=0;
va_list l;
va_start(l,len);
for(size_t i=0;i<len;i++)
{
const char *name=va_arg(l,const char *);
self->elements[i].name=malloc(strlen(name)+1);
if(!self->elements[i].name)
{
enumeration_delete(self);
return NULL;
}
strcpy(self->elements[i].name,name);
self->len++;
}
return self;
}
bool enumeration_isEqual(struct Enumeration_element_T *a,struct Enumeration_element_T *b)
{
return a->parent==b->parent && a->index==b->index;
}
bool enumeration_isName(struct Enumeration_element_T *a, const char *name)
{
return !strcmp(a->name,name);
}
const char *enumeration_getName(struct Enumeration_element_T *a)
{
return a->name;
}
struct Enumeration_element_T *enumeration_getFromName(struct Enumeration_T *self, const char *name)
{
for(size_t i=0;i<self->len;i++)
{
if(enumeration_isName(&self->elements[i],name))
{
return &self->elements[i];
}
}
return NULL;
}
struct Enumeration_element_T *enumeration_get(struct Enumeration_T *self, size_t index)
{
return &self->elements[index];
}
size_t enumeration_getCount(struct Enumeration_T *self)
{
return self->len;
}
bool enumeration_isInRange(struct Enumeration_T *self, size_t index)
{
return index<self->len;
}
int main(void)
{
struct Enumeration_T *weekdays=enumeration_create(7,"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
if(!weekdays)
{
return 1;
}
printf("Please enter the day of the week (0 to 6)\n");
size_t j = 0;
if(scanf("%zu",&j)!=1)
{
enumeration_delete(weekdays);
return 1;
}
// j=j%enumeration_getCount(weekdays); //alternative way to make sure j is in range
if(!enumeration_isInRange(weekdays,j))
{
enumeration_delete(weekdays);
return 1;
}
struct Enumeration_element_T *day=enumeration_get(weekdays,j);
printf("%s\n",enumeration_getName(day));
enumeration_delete(weekdays);
return 0;
}
The functions of enumeration should be in their own translation unit, but i combined them here to make it simpler.
The advantage is that this solution is flexible, follows the DRY principle, you can store information along with each element, you can create new enumerations during runtime and you can add new elements during runtime.
The disadvantage is that this is complex, needs dynamic memory allocation, can't be used in switch-case, needs more memory and is slower. The question is if you should not use a higher level language in cases where you need this.
Using a Macro and stringize operator(#) we can achieve this....
#include <stdio.h>
typedef enum
{
MON=0,
TUE
}week;
int main()
{
#define printt(data) printf("%s",#data);
printt(MON);
return 0;
}
i'm new to this but a switch statement will defenitely work
#include <stdio.h>
enum mycolor;
int main(int argc, const char * argv[])
{
enum Days{Sunday=1,Monday=2,Tuesday=3,Wednesday=4,Thursday=5,Friday=6,Saturday=7};
enum Days TheDay;
printf("Please enter the day of the week (0 to 6)\n");
scanf("%d",&TheDay);
switch (TheDay)
{
case Sunday:
printf("the selected day is sunday");
break;
case Monday:
printf("the selected day is monday");
break;
case Tuesday:
printf("the selected day is Tuesday");
break;
case Wednesday:
printf("the selected day is Wednesday");
break;
case Thursday:
printf("the selected day is thursday");
break;
case Friday:
printf("the selected day is friday");
break;
case Saturday:
printf("the selected day is Saturaday");
break;
default:
break;
}
return 0;
}
TheDay maps back to some integer type. So:
printf("%s", TheDay);
Attempts to parse TheDay as a string, and will either print out garbage or crash.
printf is not typesafe and trusts you to pass the right value to it. To print out the name of the value, you'd need to create some method for mapping the enum value to a string - either a lookup table, giant switch statement, etc.

Resources