Conversion de Ssortingng en Enum en C

Existe-t-il un moyen pratique de prendre une chaîne (entrée par l’utilisateur) et de la convertir en valeur d’énumération? Dans ce cas, la chaîne serait le nom de la valeur d’énumération, comme suit:

enum Day { Sunday = 0, Monday = 1, ... } 

Ainsi, si l’utilisateur donne le nom d’un jour, il pourra l’parsingr avec la valeur Enum correspondante.

Le truc, c’est que j’ai plus de 500 valeurs sur lesquelles je travaille et qu’elles sont réparties sur plusieurs énumérations.

Je connais la méthode Enum.Parse en c #, existe-t-il une forme de cela en c?

La manière standard de le mettre en œuvre est quelque chose comme:

 typedef enum {value1, value2, value3, (...) } VALUE; const static struct { VALUE val; const char *str; } conversion [] = { {value1, "value1"}, {value2, "value2"}, {value3, "value3"}, (...) }; VALUE str2enum (const char *str) { int j; for (j = 0; j < sizeof (conversion) / sizeof (conversion[0]); ++j) if (!strcmp (str, conversion[j].str)) return conversion[j].val; error_message ("no such string"); } 

L'inverse devrait être évident.

Il n’y a pas de moyen direct, mais avec C, vous improvisez. Voici un vieux truc. Les puristes peuvent hésiter à cela. Mais c’est une façon de gérer ce genre de choses de façon plutôt saine. Utilise des astuces de préprocesseur.

Dans constants.h, insérez ce qui suit:

 CONSTANT(Sunday, 0) CONSTANT(Monday, 1) CONSTANT(Tuesday, 2) 

En main.c:

 #include  #define CONSTANT(name, value) \ name = value, typedef enum { #include "constants.h" } Constants; #undef CONSTANT #define CONSTANT(name, value) \ #name, char* constants[] = { #include "constants.h" }; Constants str2enum(char* name) { int ii; for (ii = 0; ii < sizeof(constants) / sizeof(constants[0]); ++ii) { if (!strcmp(name, constants[ii])) { return (Constants)ii; } } return (Constants)-1; } int main() { printf("%s = %d\n", "Monday", str2enum("Monday")); printf("%s = %d\n", "Tuesday", str2enum("Tuesday")); return 0; } 

Vous pouvez essayer d'autres variantes de l'idée de base.

Attention, c’est un piratage total. Vous pouvez utiliser dlsym pour rechercher une variable initialisée de manière appropriée. Pour que cet exemple fonctionne, vous devez comstackr pour permettre aux symboles locaux d’être visibles par l’éditeur de liens dynamic. Avec GCC, l’option est -rdynamic .

 enum Day { SunDay, MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturDay }; enum Day Sunday = SunDay, Monday = MonDay, Tuesday = TuesDay, Wednesday = WednesDay, Thursday = ThursDay, Friday = FriDay, Saturday = SaturDay; int main () { const char *daystr = "Thursday"; void *h = dlopen(0, RTLD_NOW); enum Day *day = dlsym(h, daystr); if (day) printf("%s = %d\n", daystr, *day); else printf("%s not found\n", daystr); return 0; } 

Pas vraiment, mais si vous utilisez une fonction de hachage, vous pouvez configurer toutes les valeurs de votre enum pour qu’elles correspondent à un ensemble de chaînes hachées. Vous devrez peut-être utiliser un hachage plus compliqué si vous ne vous souciez pas de la casse.

C’est probablement votre meilleure solution car ses frais généraux sont inférieurs à ceux de strcmp (…). L’atsortingbution d’une valeur enum à partir d’un hachage de chaîne ne nécessite pas de comparaisons de chaîne répétées, etc.

Si vous utilisez directement C, il n’existe pas d’équivalent “Enum.Parse”. Vous voudrez écrire votre propre fonction, en comparant la chaîne de l’utilisateur à des valeurs prédéfinies avec strcmp() , puis en renvoyant la valeur enum appropriée.

Une autre possibilité consiste à utiliser une implémentation “hash map” existante, ou à déployer la vôtre – par exemple, celle de glib devrait fonctionner pour vous: https://developer.gnome.org/glib/2.30/glib-Hash-Tables.html

Une carte de hachage devrait être plus rapide qu’une recherche linéaire sur les valeurs énumérées possibles, si vous en avez beaucoup (par exemple, si vous faites autre chose que les jours de la semaine). Une bonne implémentation de la carte de hachage doit être proche de O (1) pour les recherches, au lieu de O (n) pour une recherche linéaire.

Ce serait une bonne solution:

 enum e_test { a, b, c, END }; enum e_test get_enum_value(char * val) { static char const * e_test_str[] = { "a", "b", "c" }; for (int i = 0; i < END; ++i) if (!strcmp(e_test_str[i], val)) return i; return END; }