C MacroMagic - определение структуры - PullRequest
0 голосов
/ 26 сентября 2018

Я ищу решение для определения структуры, где пользователь может включить / отключить элементы структуры, как в примере (псевдокод):

#define DEF_STRUCT_1(NAME,VAL1,VAL2)      \
    struct my_struct_t                    \
    {                                     \
      #if(NAME == TRUE)                   \
        bool name;                        \
      #endif                              \
      #if(VAL1 == TRUE)                   \
        bool val1;                        \
      #endif                              \
      #if(VAL2 == TRUE)                   \
        bool val2;                        \
      #endif                              \
    } instance1

void main() {
  DEF_STRUCT_1(TRUE,FALSE,TRUE);

  instance1.name = true;
  //instance1.val1 = false; // error, unavailable
  instance1.val2 = false;
}

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

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

Существует хорошо известный шаблон проектирования, известный как «X-макросы», который можетиспользоваться для централизации обслуживания в программах в одном месте, а также позволяет выполнять итерации во время компиляции всех элементов.Они также затрудняют чтение кода, и поэтому они являются последним средством.Но они являются стандартом де-факто, и их уродство не масштабируется со сложностью, поэтому они предпочитаются некоторому безумию переключателя компилятора.Это выглядит так:

#define INSTANCE_LIST \
/*  name, type */     \  
  X(name, bool)       \
  X(val1, bool)       \
  X(val2, bool)       \

typedef struct
{
  #define X(name, type) type name;
    INSTANCE_LIST
  #undef X
} instance_t;

Этот код предварительно обрабатывается в:

typedef struct
{
  bool name;
  bool val1;
  bool val2;
} instance_t;

Единственная часть, которую необходимо сохранить, это "INSTANCE_LIST".Закомментировав строку в списке, этот член структуры исчезнет.Это означает, что весь код, использующий структуру, должен соответственно использовать один и тот же список.Например, давайте добавим код в тот же пример, который перечисляет значения инициализации каждого члена и затем устанавливает их:

#include <stdbool.h>
#include <stdio.h>

#define INSTANCE_LIST       \
/*  name, type, init */     \  
  X(name, bool, true)       \
  X(val1, bool, false)      \
  X(val2, bool, false)      \

typedef struct
{
  #define X(name, type, init) type name;
    INSTANCE_LIST
  #undef X
} instance_t;

int main (void)
{
  instance_t inst;

  #define X(name, type, init) inst.name = init;
    INSTANCE_LIST
  #undef X

  printf("%d ", inst.name);
  printf("%d ", inst.val1);
  printf("%d ", inst.val2);
}

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

0 голосов
/ 26 сентября 2018

Я не уверен, насколько это полезно, но следующее должно делать то, что вы просите:

#define CONDITIONAL_TRUE(code) code
#define CONDITIONAL_FALSE(code)

#define DEF_STRUCT_1(NAME,VAL1,VAL2)      \
    struct my_struct_t                    \
    {                                     \
      CONDITIONAL_##NAME(bool name;)      \
      CONDITIONAL_##VAL1(bool val1;)      \
      CONDITIONAL_##VAL2(bool val2;)      \
    } instance1

int main() {
  DEF_STRUCT_1(TRUE,FALSE,TRUE);

  instance1.name = true;
  //instance1.val1 = false; // error, unavailable
  instance1.val2 = false;
}

Все параметры TRUE / FALSE должны быть доступны во время компиляции,И если вы хотите, чтобы в одной и той же программе использовалось более одной версии этих параметров, вы должны также сделать имя структуры параметром.

Поскольку вы говорите, что это предназначено для библиотеки, это не так.Понятно, как вы планируете, чтобы код библиотеки мог получить доступ к этой структуре, так как ей нужно было бы знать, какие члены доступны.Это значительно снижает полезность этого метода.

Более распространенным методом, используемым библиотеками, является наличие файла config.h, редактируемого пользователем библиотеки, с определениями, такими как #define USE_NAME_MEMBER 1.Затем вы можете создать нормальное struct определение с директивами #if:

//in mylibrary.h:
#include <mylibrary_config.h>

struct my_struct_t {
    #if USE_NAME_MEMBER
        bool name;
    #endif
    /...
};

Затем вы также поместите директивы #if вокруг любого библиотечного кода, который обращается к члену name.

...