HiveBrain v1.2.0
Get Started
← Back to all entries
patterncModerate

Generic enum to text lookup in C

Submitted by: @import:stackexchange-codereview··
0
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 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:

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.