Технический приём для формирования согласованных данных - C (СИ)

Узнай цену своей работы

Формулировка задачи:

Кому-то может пригодиться Если нет чёткого представления о том, как работает препроцессирование, то смотрим сюда (про директиву #include) и сюда (про директиву #define) Допустим, нужно сделать две согласованных конструкции
enum
{
  ENUM_VAL1,
  ENUM_VAL2,
  ENUM_VAL3,
};
 
char *names[] =
{
  "VAL1",
  "VAL2",
  "VAL3",
};
При этом элемент enum'а является индексом в массив, для доставания соотвествующего строкового значения. Если нам нужно что-то добавить, то надо править в двух местах, которые, как правило в разных файлах. А когда файлы большие и подобных данных много, то можно запутаться. Если изменить только enum (особенно если добавить элемент в середину), то names станет несогласованным. А потому нужно такое решение, чтобы каждый элемент условно задавался одной строкой, чтобы во все места подставились нужные данные. Для этого делаю дополнительный файл. У меня он имеет расширение *.def, но это непринципииально (у gnu'шников он *.def, а потому я тоже так делаю, чтобы как у людей было) В итоге получается такая штука
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")
В итоге после подстановки директив #include на этапе прероцессирования получаем файл
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",
};
Такми образом инициализаторы от двух разных конструкций у на оказываются в одной строке. Добавление новых элементов о\существляется только в файл *.def

Решение задачи: «Технический приём для формирования согласованных данных»

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. Список элементов перечисления формируется следующим образом:

  1. enum — объявление перечисления.
  2. #define DEF_ELEM(p1,p2) p1, — определение элемента перечисления. Значение — p1, имя — p2.
  3. #include file1.def — включение содержимого файла file1.def.
  4. #undef DEF_ELEM — отмена определения элемента перечисления.
  5. #define DEF_ELEM(p1,p2) p1 — определение элемента перечисления. Значение — p1, имя — p2.
  6. #include file2.def — включение содержимого файла file2.def.
  7. #undef DEF_ELEM — отмена определения элемента перечисления. Список строк формируется аналогично, только вместо значений используется строка, которая идет после определения элемента перечисления. В результате, в переменной names будет храниться массив строк, а в переменной enum — перечисление, которые будут содержать согласованные данные из файлов file1.def и file2.def.

Оцени полезность:

14   голосов , оценка 4 из 5
Похожие ответы