patterncModerate
Generic enum to text lookup in C
Viewed 0 times
generictextenumlookup
Problem
Can my code from this question be improved? I am thiking of validating inputs, portability issues, etc
Please note that we must declare our strings at compile time. We code embedded systems and are not allowed to
[Update]
I forgot to state that our enums are non-contiguous and have a wide range, which can make a difference.
Here's some test data:
and, here's the code, which should get text from an enum, as defined by a struct of enum/string, where different structs can have different length arrays.:
```
#define ARRAY_LENGTH(A) sizeof(A) / sizeof(*A)
char *Get_text_from_enum(int enum_value,
void *array,
unsigned int array_length,
unsigned int size_of_array_entry)
{
unsigned int i;
unsigned int offset;
for (i = 0; i < array_length; i++)
{
offset = i * size_of_array_entry;
if ((int) ((int ) (array+ offset)) == enum_value)
return (char *) (array + offset + sizeof(int));
}
return NULL;
}
printf("Expect south, got %s\n",
Get_text_from_enum(south,
direction_data,
ARRAY_LENGTH(direction_data),
sizeof(direction_data[0])));
printf("Expect diamonds, got %s\n",
Please note that we must declare our strings at compile time. We code embedded systems and are not allowed to
malloc().[Update]
I forgot to state that our enums are non-contiguous and have a wide range, which can make a difference.
Here's some test data:
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=
typedef enum
{
north,
south,
east,
west
} E_directions;
struct direction_datum
{
E_directions direction;
char direction_name[6];
};
struct direction_datum direction_data[] =
{
{north, "north"},
{south, "south"},
{east, "east"},
{west, "west"},
};
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=
typedef enum
{
hearts,
spades,
diamonds,
clubs,
} E_suits;
struct suit_datum
{
E_suits suit;
char suit_name[9];
};
struct suit_datum suit_data[] =
{
{hearts, "hearts"},
{spades, "spades"},
{diamonds, "diamonds",},
{clubs, "clubs"},
};and, here's the code, which should get text from an enum, as defined by a struct of enum/string, where different structs can have different length arrays.:
```
#define ARRAY_LENGTH(A) sizeof(A) / sizeof(*A)
char *Get_text_from_enum(int enum_value,
void *array,
unsigned int array_length,
unsigned int size_of_array_entry)
{
unsigned int i;
unsigned int offset;
for (i = 0; i < array_length; i++)
{
offset = i * size_of_array_entry;
if ((int) ((int ) (array+ offset)) == enum_value)
return (char *) (array + offset + sizeof(int));
}
return NULL;
}
printf("Expect south, got %s\n",
Get_text_from_enum(south,
direction_data,
ARRAY_LENGTH(direction_data),
sizeof(direction_data[0])));
printf("Expect diamonds, got %s\n",
Solution
Illegal void pointer arithmetic
This code is illegal in C:
You are not allowed to do pointer arithmetic on a
Simplifications
I would suggest defining a generic structure like this:
to avoid all of the struct length shenanigans. You can also make it a rule that each
This code is illegal in C:
void *array;
... (array + offset)You are not allowed to do pointer arithmetic on a
void pointer. You should use char instead of void *.Simplifications
I would suggest defining a generic structure like this:
typedef struct EnumName {
int value;
const char *name;
} EnumName;to avoid all of the struct length shenanigans. You can also make it a rule that each
EnumName array must be terminated with a NULL name. This rule allows you to avoid passing in an array length argument. Then your code would look like this:const EnumName direction_data[] =
{
{north, "north"},
{south, "south"},
{east, "east" },
{west, "west" },
{0, NULL },
};
const char *Get_text_from_enum(int enum_value, const EnumName *names)
{
while (names->value != enum_value && names->name != NULL)
names++;
return names->name;
}
int main(void)
{
printf("Expect south, got %s\n",
Get_text_from_enum(south, direction_data));
}Code Snippets
void *array;
... (array + offset)typedef struct EnumName {
int value;
const char *name;
} EnumName;const EnumName direction_data[] =
{
{north, "north"},
{south, "south"},
{east, "east" },
{west, "west" },
{0, NULL },
};
const char *Get_text_from_enum(int enum_value, const EnumName *names)
{
while (names->value != enum_value && names->name != NULL)
names++;
return names->name;
}
int main(void)
{
printf("Expect south, got %s\n",
Get_text_from_enum(south, direction_data));
}Context
StackExchange Code Review Q#150480, answer score: 12
Revisions (0)
No revisions yet.