Pergunta

Qual é a melhor abordagem para definir dados adicionais para enums typedef em C?

Exemplo:

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

Agora eu gostaria de definir nomes para cada um, por exemplo kVizsla deveria ser "vizsla".Atualmente uso uma função que retorna uma string usando um grande bloco de switch.

Foi útil?

Solução

@dmckee:Acho que a solução sugerida é boa, mas para dados simples (por exemplose apenas o nome for necessário) ele poderá ser aumentado com código gerado automaticamente.Embora existam muitas maneiras de gerar código automaticamente, para algo tão simples como isso, acredito que você poderia escrever um XSLT simples que receba uma representação XML da enumeração e gere o arquivo de código.

O XML ficaria no formato:

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

e o código resultante seria algo semelhante ao que dmckee sugeriu em sua solução.

Para obter informações sobre como escrever tal XSLT, tente aqui ou apenas pesquise no Google e encontre um tutorial adequado.Escrever XSLT não é muito divertido, mas também não é tão ruim assim, pelo menos para tarefas relativamente simples como essas.

Outras dicas

Um ajuste perfeito para Macros X().Esses tipos de macros podem usar o pré-processador C para construir enumerações e matrizes da mesma fonte.Você só precisa adicionar novos dados ao #define que contém a macro X().

Seu exemplo pode ser escrito da seguinte forma:

// 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 seus valores enumerados forem densos o suficiente, você poderá definir um array para armazenar as strings e apenas procurá-las (use NULL para qualquer valor ignorado e adicione um manipulador de caso especial em sua rotina de pesquisa).

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

Isso é ineficiente para enumerações esparsas.

Mesmo que a enumeração não seja densa, você pode usar uma matriz de estruturas para conter o mapeamento.

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

A segunda abordagem é muito flexível, mas significa uma pesquisa no mapeamento sempre que precisar usar os dados.Para grandes conjuntos de dados, considere uma árvore b ou hash em vez de uma matriz.

Qualquer um dos métodos pode ser generalizado para conectar mais dados.No primeiro use um array de structs, no segundo basta adicionar mais membros à struct.

É claro que você desejará escrever vários manipuladores para simplificar sua interação com essas estruturas de dados.


@Hershi Por suposto, separe o código e os dados.Os exemplos acima pretendem ser claros e não funcionais.

Eu coro ao admitir que ainda uso arquivos simples separados por espaços em branco para essa finalidade, em vez do tipo de entrada estruturada que você exibe, mas meu código de produção leria o máximo possível de dados de fontes externas.


Espere, vejo que você quer dizer geração de código.

Claro.Nada de errado com isso.

Eu suspeito, porém, que o OP estava interessado em como deveria ser o código gerado ...

Essa é uma pergunta aberta, mas uma sugestão seria usar um mapa com o enum como tipo de chave e as informações extras no valor.(Se seus índices forem contínuos, diferentemente do exemplo, você poderá usar um contêiner de sequência em vez de um mapa).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top