Domanda

Qual è l'approccio migliore per definire dati aggiuntivi per le enumerazioni typedef in C?

Esempio:

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

Ora vorrei definire i nomi per ciascuno, ad esempio kVizsla dovrebbe essere "vizsla".Attualmente utilizzo una funzione che restituisce una stringa utilizzando un grande blocco di interruttori.

È stato utile?

Soluzione

@dmckee:Penso che la soluzione suggerita sia buona, ma per dati semplici (ad es.se è necessario solo il nome) potrebbe essere arricchito con codice generato automaticamente.Sebbene esistano molti modi per generare automaticamente il codice, per qualcosa di così semplice credo che potresti scrivere un semplice XSLT che includa una rappresentazione XML dell'enumerazione e restituisca il file di codice.

L'XML sarebbe nel formato:

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

e il codice risultante sarebbe qualcosa di simile a quello suggerito da dmckee nella sua soluzione.

Per informazioni su come scrivere un XSLT di questo tipo, provare Qui o semplicemente cercalo su Google e trova un tutorial adatto.Scrivere XSLT non è molto divertente, secondo me, ma non è nemmeno così male, almeno per compiti relativamente semplici come questi.

Altri suggerimenti

Una soluzione perfetta per X() macro.Questi tipi di macro possono utilizzare il preprocessore C per costruire enumerazioni e array dalla stessa origine.Devi solo aggiungere nuovi dati al #define contenente la macro X().

Il tuo esempio può essere scritto come segue:

// 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);

Se i valori enumerati sono abbastanza densi, puoi definire un array per contenere le stringhe e semplicemente cercarle (usa NULL per qualsiasi valore saltato e aggiungi un gestore di casi speciali nella tua routine di ricerca).

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

Ciò è inefficiente per le enumerazioni sparse.

Anche se l'enumerazione non è densa, puoi utilizzare un array di strutture per contenere la mappatura.

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

Il secondo approccio è molto flessibile, ma implica una ricerca nella mappatura ogni volta che è necessario utilizzare i dati.Per set di dati di grandi dimensioni considerare un b-tree o un hash anziché un array.

Entrambi i metodi possono essere generalizzati per connettere più dati.Nel primo utilizzo un array di strutture, nel secondo basta aggiungere più membri alla struttura.

Naturalmente vorrai scrivere vari gestori per semplificare la tua interazione con queste strutture dati.


@Hershi Sicuramente, codice e dati separati.Gli esempi sopra riportati vogliono essere chiari piuttosto che funzionali.

Arrossisco nell'ammettere che utilizzo ancora file flat separati da spazi bianchi per quello scopo, piuttosto che il tipo di input strutturato che mostri, ma il mio codice di produzione leggerebbe la maggior parte possibile di dati da fonti esterne.


Aspetta, vedo che intendi la generazione di codice.

Sicuro.Non c'è niente di sbagliato in questo.

Sospetto, tuttavia, che l'OP fosse interessato a come dovrebbe apparire il codice generato ...

È una specie di domanda aperta, ma un suggerimento sarebbe quello di utilizzare una mappa con l'enumerazione come tipo di chiave e le informazioni aggiuntive nel valore.(Se i tuoi indici sono continui, a differenza dell'esempio, puoi utilizzare un contenitore di sequenza invece di una mappa).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top