Добавить предопределенные данные для перечислений typedef в C - PullRequest
4 голосов
/ 30 августа 2008

Каков наилучший подход для определения дополнительных данных для перечислений typedef в C?

Пример:

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

Теперь я хотел бы определить имена для каждого, например kVizsla должно быть "визсла". В настоящее время я использую функцию, которая возвращает строку, используя большой блок переключателей.

Ответы [ 4 ]

3 голосов
/ 02 сентября 2008

Идеально подходит для X () макросов . Эти типы макросов могут использовать препроцессор C для создания перечислений и массивов из одного источника. Вам нужно только добавить новые данные в #define, содержащий макрос X ().

Ваш пример можно записать следующим образом:

// 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);
2 голосов
/ 30 августа 2008

@ dmckee: Я думаю, что предложенное решение хорошо, но для простых данных (например, если требуется только имя) оно может быть дополнено автоматически сгенерированным кодом. Хотя существует множество способов автоматической генерации кода, для чего-то столь простого, я полагаю, вы могли бы написать простой XSLT, который принимает XML-представление перечисления и выводит файл кода.

XML будет иметь вид:

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

и полученный код будет чем-то похожим на то, что dmckee предложил в своем решении.

Для получения информации о том, как написать такой XSLT, попробуйте здесь или просто найдите его в Google и найдите подходящее учебное пособие. Написание XSLT не очень забавно для ИМО, но и не так уж плохо, по крайней мере для относительно простых задач, таких как эти.

1 голос
/ 30 августа 2008

Если ваши перечисленные значения достаточно плотные, вы можете определить массив для хранения строк и просто найти их (используйте NULL для любого пропущенного значения и добавьте специальный обработчик в своей процедуре поиска).

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

Это неэффективно для разреженных перечислений.

Даже если перечисление не плотное, вы можете использовать массив структур для хранения отображения.

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

Второй подход очень гибкий, но он подразумевает поиск по карте каждый раз, когда вам нужно использовать данные. Для больших наборов данных рассмотрите b-дерево или хеш вместо массива.

Любой метод может быть обобщен для подключения большего количества данных. В первом используйте массив структур, во втором просто добавьте больше членов в структуру.

Конечно, вы захотите написать различные обработчики, чтобы упростить ваше взаимодействие с этими структурами данных.


@ Hershi Во что бы то ни стало, отдельный код и данные. Приведенные выше примеры предназначены для ясности, а не функциональности.

Я смущаюсь, признав, что для этой цели я по-прежнему использую плоские файлы, разделенные пробелами, а не тот структурированный ввод, который вы демонстрируете, но мой производственный код будет считывать как можно больше данных из внешних источников.


Подождите, я вижу, что вы имеете в виду генерацию кода.

Конечно. В этом нет ничего плохого.

Я подозреваю, что ОП интересовало, как должен выглядеть сгенерированный код ...

0 голосов
/ 30 августа 2008

Это своего рода открытый вопрос, но одним из предложений будет использование карты с перечислением в качестве типа ключа и дополнительной информацией в значении. (Если ваши индексы непрерывны, в отличие от примера, вы можете использовать контейнер последовательности вместо карты).

...