Sharing Text Search in C

[Update]


[Update ++] I will probably accept one of the answers below. However, I forgot to point out that our listings are non-contiguous and have a wide range, which can make a difference.


Mezhtubki and this site are awash with questions requiring a text from the listing.

I cannot find a canonical way to do this (and would take it as an answer to this question), so let's see if we can cross each other between us.

In our code, we have several arrays of structures containing pairs of enumerations and corresponding strings.

The problem is that the strings have different lengths, so we code a search function for each of them, which for loops over an array of structures, trying to match the enumeration and return the corresponding text if a match is found.

Let's take the following two far-fetched examples:

// +=+=+=+=+=+=+=+=+=+=+=+=+=+=
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"},
};

In addition to the length of the string, they are the same / identical, so theoretically we should be able to encode the generalized function for the loop through direction_dataor suit_data, taking into account the index and return of the corresponding text.

, - , ( zer0, , , ).

?

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", 
          Get_text_from_enum(diamonds, 
                             suit_data,      
                             ARRAY_LENGTH(suit_data),       
                             sizeof(suit_data[0])));
+3
2

, . , .

struct enum_datum  
{
    int    enum_val;
    char  *enum_name;
};

char *GetEnumName(enum_datum *table, int value)
{
   while (table->enum_name != NULL)
   {
      if (table->enum_val == value)
         return enum_name;
      table++;
   }
   return NULL;
}

:

typedef enum {
    north, south, east, west
} E_directions;

enum_datum E_directions_datum[] = 
{
    { north, "north" },
    { south, "south" },
    { east,  "east"  },
    { west,  "west"  },
    { some_value_not_important, NULL }, // The end of the array marker.
};

char *GetDirectionName(E_directions dir)
{
    return GetEnumName(E_directions_datum, dir);
}

, , . enum_datum . .

. .

+2

"" . , , .


" " - , . , :

typedef enum
{
    north,
    south,
    east,
    west,
    directions_n // only used to keep track of the amount of enum constants
} direction_t;

const char* STR_DIRECTION [] =  // let array size be based on number of items
{
  "north",
  "south",
  "east",
  "west"
};


#define ARRAY_ITEMS(array) (sizeof(array) / sizeof(*array))
...
// verify integrity of enum and look-up table both:
_Static_assert(directions_n == ARRAY_ITEMS(STR_DIRECTION), 
               "direction_t does not match STR_DIRECTION");

, , :

typedef struct
{
  direction_t dir;
  const char* str;
} dir_struct_t;

const dir_struct_t DIRS [directions_n] = 
{ // use designated initializers to guarantee data integrity even if item order is changed:
  [north] = {north, STR_DIRECTION[north]},
  [south] = {south, STR_DIRECTION[south]},
  [east]  = {east,  STR_DIRECTION[east]},
  [west]  = {west,  STR_DIRECTION[west]}
};

"X-", , , , , , , .

:

#define DIRECTION_LIST \
  X(north), \
  X(south), \
  X(east),  \
  X(west),         // trailing commma important here! (and ok in enums since C99)

typedef enum
{
  #define X(dir) dir
    DIRECTION_LIST
  #undef X
  directions_n // only used to keep track of the amount of enum constants
} direction_t;

typedef struct
{
  direction_t dir;
  const char* str;
} dir_struct_t;

const dir_struct_t DIRS [directions_n] = 
{
  #define X(dir) {dir, #dir}
    DIRECTION_LIST
  #undef X
};

.

+5

Source: https://habr.com/ru/post/1683746/


All Articles