Технический приём для формирования согласованных данных - C (СИ)
Формулировка задачи:
Кому-то может пригодиться
Если нет чёткого представления о том, как работает препроцессирование, то смотрим сюда (про директиву #include) и сюда (про директиву #define)
Допустим, нужно сделать две согласованных конструкции
При этом элемент enum'а является индексом в массив, для доставания соотвествующего строкового значения. Если нам нужно что-то добавить, то надо править в двух местах, которые, как правило в разных файлах. А когда файлы большие и подобных данных много, то можно запутаться. Если изменить только enum (особенно если добавить элемент в середину), то names станет несогласованным.
А потому нужно такое решение, чтобы каждый элемент условно задавался одной строкой, чтобы во все места подставились нужные данные. Для этого делаю дополнительный файл. У меня он имеет расширение *.def, но это непринципииально (у gnu'шников он *.def, а потому я тоже так делаю, чтобы как у людей было)
В итоге получается такая штука
В итоге после подстановки директив #include на этапе прероцессирования получаем файл
Теперь смотрим, как макросы подстанавливаются
раскроется как
а
раскроется как
В итоге весь файл после препроцессирования окажется вот таким
Такми образом инициализаторы от двух разных конструкций у на оказываются в одной строке. Добавление новых элементов о\существляется только в файл *.def
enum
{
ENUM_VAL1,
ENUM_VAL2,
ENUM_VAL3,
};
char *names[] =
{
"VAL1",
"VAL2",
"VAL3",
};enum
{
#define DEF_ELEM(p1,p2) p1,
#include "file.def"
#undef DEF_ELEM
};
char *names[] =
{
#define DEF_ELEM(p1,p2) p2,
#include "file.def"
#undef DEF_ELEM
};/* Файл file.def */ DEF_ELEM (ENUM_VAL1, "VAL1") DEF_ELEM (ENUM_VAL2, "VAL2") DEF_ELEM (ENUM_VAL3, "VAL3")
enum
{
#define DEF_ELEM(p1,p2) p1,
DEF_ELEM (ENUM_VAL1, "VAL1")
DEF_ELEM (ENUM_VAL2, "VAL2")
DEF_ELEM (ENUM_VAL3, "VAL3")
#undef DEF_ELEM
};
char *names[] =
{
#define DEF_ELEM(p1,p2) p2,
DEF_ELEM (ENUM_VAL1, "VAL1")
DEF_ELEM (ENUM_VAL2, "VAL2")
DEF_ELEM (ENUM_VAL3, "VAL3")
#undef DEF_ELEM
};#define DEF_ELEM(p1,p2) p1, DEF_ELEM (ENUM_VAL1, "VAL1")
ENUM_VAL1,
#define DEF_ELEM(p1,p2) p2, DEF_ELEM (ENUM_VAL1, "VAL1")
"VAL1",
enum
{
ENUM_VAL1,
ENUM_VAL2,
ENUM_VAL3,
};
char *names[] =
{
"VAL1",
"VAL2",
"VAL3",
};Решение задачи: «Технический приём для формирования согласованных данных»
textual
Листинг программы
enum
{
#define DEF_ELEM(p1,p2) p1,
#include "file1.def"
#undef DEF_ELEM
#define DEF_ELEM(p1,p2) p1
#include "file2.def"
#undef DEF_ELEM
};
char *names[] =
{
#define DEF_ELEM(p1,p2) p2,
#include "file1.def"
#undef DEF_ELEM
#define DEF_ELEM(p1,p2) p2
#include "file2.def"
#undef DEF_ELEM
};
Объяснение кода листинга программы
В представленном коде используется препроцессор для формирования согласованных данных. Список именованных чисел и их значений в виде перечисления (enum) и массива строк (char *names[]) формируются из данных, которые находятся в файлах file1.def и file2.def. Список элементов перечисления формируется следующим образом:
- enum — объявление перечисления.
- #define DEF_ELEM(p1,p2) p1, — определение элемента перечисления. Значение —
p1, имя —p2. - #include
file1.def— включение содержимого файла file1.def. - #undef DEF_ELEM — отмена определения элемента перечисления.
- #define DEF_ELEM(p1,p2) p1 — определение элемента перечисления. Значение —
p1, имя —p2. - #include
file2.def— включение содержимого файла file2.def. - #undef DEF_ELEM — отмена определения элемента перечисления.
Список строк формируется аналогично, только вместо значений используется строка, которая идет после определения элемента перечисления.
В результате, в переменной
namesбудет храниться массив строк, а в переменнойenum— перечисление, которые будут содержать согласованные данные из файлов file1.def и file2.def.