Question

Quelle est la meilleure approche pour définir des données supplémentaires pour les énumérations typedef en C ?

Exemple:

typedef enum {
  kVizsla = 0,
  kTerrier = 3,
  kYellowLab = 10
} DogType;

Maintenant, je voudrais définir des noms pour chacun, par exemple kVizsla devrait être "vizsla".J'utilise actuellement une fonction qui renvoie une chaîne à l'aide d'un gros bloc de commutation.

Était-ce utile?

La solution

@dmckee :Je pense que la solution suggérée est bonne, mais pour des données simples (par ex.si seul le nom est nécessaire), il pourrait être complété par du code généré automatiquement.Bien qu'il existe de nombreuses façons de générer automatiquement du code, pour quelque chose d'aussi simple que cela, je pense que vous pouvez écrire un simple XSLT qui prend en compte une représentation XML de l'énumération et génère le fichier de code.

Le XML serait de la forme :

<EnumsDefinition>
    <Enum name="DogType">
        <Value name="Vizsla" value="0" />
        <Value name="Terrier" value="3" />
        <Value name="YellowLab" value="10" />
    </Enum>
</EnumsDefinition>

et le code résultant serait quelque chose de similaire à ce que dmckee a suggéré dans sa solution.

Pour plus d'informations sur la façon d'écrire un tel XSLT, essayez ici ou recherchez-le simplement dans Google et trouvez un tutoriel qui vous convient.Écrire XSLT n'est pas très amusant à mon avis, mais ce n'est pas si mal non plus, du moins pour des tâches relativement simples comme celles-ci.

Autres conseils

Un ajustement parfait pour Macro X().Ces types de macros peuvent utiliser le préprocesseur C pour construire des énumérations et des tableaux à partir de la même source.Il vous suffit d'ajouter de nouvelles données au #define contenant la macro X().

Votre exemple peut s'écrire comme suit :

// All dog data goes in this list
#define XDOGTYPE \
  X(kVizsla,0,"vizsla") \
  X(kTerrier,3,"terrier") \
  X(kYellowLab,10,"yellowlab")

 // Dog info
 typedef struct {
     int val;       // Defined value
     char * desc;   // Text description
 } DogType;

 // Build an array index using the Names
 typedef enum {
  #define X(Name,Val,Text)     Name,
   XDOGTYPE
  #undef X
  MAXDOGS
 } DogIndex;

 // Build a lookup table of values
 DogType Dog[] = {
  #define X(Name,Val,Text)    {Val,Text},
   XDOGTYPE
  #undef X
 };

 // Access the values
 for (i=0; i < MAXDOGS; i++)
    printf("%d: %s\n",Dog[i].val,Dog[i].desc);

Si vos valeurs énumérées sont suffisamment denses, vous pouvez définir un tableau pour contenir les chaînes et simplement les rechercher (utilisez NULL pour toute valeur ignorée et ajoutez un gestionnaire de cas spécial à votre routine de recherche).

char *DogList[] = {
  "vizsla", /* element 0 */
  NULL,
  NULL,
  NULL,
  "terrier", /* element 3 */
  ...
};

Ceci est inefficace pour les énumérations clairsemées.

Même si l'énumération n'est pas dense, vous pouvez utiliser un tableau de structures pour contenir le mappage.

typedef struct DogMaps {
  DogType index;
  char * name;
} DogMapt;
DogMapt DogMap[] = {
  {kVizsla, "vizsla"},
  {kTerrier, "terrier"},
  {kYellowLab, "yellow lab"},
  NULL
};

La deuxième approche est très flexible, mais elle implique une recherche dans la cartographie à chaque fois que vous avez besoin d'utiliser les données.Pour les grands ensembles de données, envisagez un arbre B ou un hachage au lieu d'un tableau.

L’une ou l’autre méthode peut être généralisée pour connecter davantage de données.Dans le premier, utilisez un tableau de structures, dans le second, ajoutez simplement plus de membres à la structure.

Vous souhaiterez bien sûr écrire différents gestionnaires pour simplifier votre interaction avec ces structures de données.


@Hershi Bien sûr, séparez le code et les données.Les exemples ci-dessus se veulent clairs plutôt que fonctionnels.

Je rougis d'admettre que j'utilise toujours des fichiers plats séparés par des espaces à cette fin, plutôt que le type d'entrée structurée que vous présentez, mais mon code de production lirait autant de données provenant de sources externes que possible.


Attendez, je vois que vous parlez de génération de code.

Bien sûr.Aucun problème avec cela.

Je soupçonne cependant que l'OP était intéressé par ce à quoi devrait ressembler le code généré...

C'est une sorte de question ouverte, mais une suggestion serait d'utiliser une carte avec l'énumération comme type de clé et les informations supplémentaires dans la valeur.(Si vos indices sont continus, contrairement à l'exemple, vous pouvez utiliser un conteneur de séquence au lieu d'une carte).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top