Добавление предопределенных данных для перечислений typedef в C
Вопрос
Каков наилучший подход к определению дополнительных данных для перечислений typedef в C?
Пример:
typedef enum {
kVizsla = 0,
kTerrier = 3,
kYellowLab = 10
} DogType;
Теперь я хотел бы определить имена для каждого из них, например kVizsla
должно быть "визсла".В настоящее время я использую функцию, которая возвращает строку, используя большой блок переключения.
Решение
@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 не очень весело, IMO, но и не так уж плохо, по крайней мере, для относительно простых задач, подобных этой.
Другие советы
Идеально подходит для 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);
Если ваши перечисленные значения достаточно плотные, вы можете определить массив для удержания струн и просто посмотреть их (используйте 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-три или хэш вместо массива.
Любой метод может быть обобщен для подключения дополнительных данных. В первом использовании массива структур, во втором, просто добавьте больше членов в структуру.
Вы, конечно, хотите написать различные обработчики, чтобы упростить ваше взаимодействие с этими структурами данных.
@Hersshi во что бы то ни стало, отдельный код и данные. Приведенные выше примеры должны быть четкими, а не функциональными.
Я краснею, чтобы признать, что для этой цели все еще использую отдельные плоские файлы, а не тот тип структурированного ввода, который вы демонстрируете, но мой производственный код будет читать как можно больше данных из внешних источников.
Подождите, я вижу, что вы имеете в виду генерацию кода.
Конечно. В этом нет ничего плохого.
Я подозреваю, что однако, что OP интересовался тем, как должен выглядеть сгенерированный код ...
Это своего рода открытый вопрос, но одним из предложений было бы использовать карту с перечислением в качестве типа ключа и дополнительной информации в значении. (Если ваши индексы непрерывны, в отличие от примера, вы можете использовать контейнер последовательности вместо карты).