Члены массива, определенные как константы - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь реализовать фреймворк, в котором мне нужно объявить (в файле .h) список доступных «драйверов» (переменных структуры), которые будут определены в конкретных модулях .c.Поскольку в будущем список, вероятно, будет расти, я бы хотел, чтобы все это было в одном месте в файле .h, чтобы его можно было легко расширять.

Например, давайте получим "driver.h"

typedef struct driver {
    int id;
    char name[10];
    int(*init)();
    void (*deinit)();
    int (*doTheJob)(int);
} driver_t;

#define DRIVERLIST driver1, driver2, driver3
#define DRIVERS extern driver_t DRIVERLIST;

DRIVERS

Тогда конкретные драйверы (driver1, driver2, driver3) будут определены в выделенных модулях .. например, driver1.c, driver2.c .. и т.д ...

Но тогда я бы хотел иметьмодуль, например manager.c, где я хотел бы определить массив доступных драйверов, как объявлено в driver.h, так что я могу перебирать массив и получать драйверы для использования в других частях фреймворка.

Так что в manager.c мне нужно что-то вроде:

driver_t drivers[MAX_DRIVERS] = {DRIVERS}

Но, очевидно, он не компилируется таким образом. Основная идея - редактировать только driver.h, когда мне нужно добавить объявление для дополнительногодрайвер в будущем, а затем просто внедрить его в выделенный модуль, без необходимости редактировать, например, manager.c или другие части фреймворка. У вас есть идеи, как реализовать такой механизм в c?

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Правильный способ сделать это в C - это немедленно избавиться от всех extern -спагетти с глобалами.

Вместо этого вы можете поместить определение структуры внутри driver.h и в driver.c инициализировать его через «конструктор»:

// driver.c
#include "driver.h"
#include "specific_driver_x.h"

void driver_init (driver_t* driver)
{
  driver->init = specific_driver_init;
  driver->doTheJob = specific_driver_job;
}

Для профессионального кода это может быть улучшено с помощьюПонятие «непрозрачный тип», как объяснено здесь , для достижения частной инкапсуляции (и при необходимости полиморфизма).В этом случае определение структуры может быть (частично) скрыто в driver.c, и конструктор также обрабатывает выделение памяти.

0 голосов
/ 17 октября 2018

Я думаю, что нашел решение.Я черпал вдохновение из проекта rtl_433 https://github.com/merbanan/rtl_433/blob/master/include/rtl_433_devices.h, где они определили что-то похожее для объявлений устройств.

Так должно быть в заголовочном файле:

/* driver.h */
#define DRIVERS \
    DECL(driver1) \
    DECL(driver2) 


#define DECL(name) extern driver_t name;
    DRIVERS
#undef DECL

А затем вмодуль:

/* driver.c */

driver_t* drivers[] = {  
#define DECL(name) &name,
    DRIVERS
#undef DECL
};
0 голосов
/ 16 октября 2018

В C вы не можете инициализировать массив с копиями некоторых объектов (в C ++ это возможно, но это не очень хорошая практика, потому что они копии и будут изменены независимо от оригинальных объектов).

drivers массив должен содержать указатели на исходные объекты.Я предлагаю что-то вроде

/* driver.h */
typedef struct driver {
    int id;
    char name[10];
    int(*init)();
    void (*deinit)();
    int (*doTheJob)(int);
} driver_t;

#define MAX_DRIVERS 10

#define DRIVERLIST driver1, driver2, driver3
#define DRIVERS_INIT {&driver1, &driver2, &driver3}

#define DRIVERS extern driver_t DRIVERLIST;

DRIVERS
/* manager.c */
#include "driver.h"

/* ... */

driver_t * drivers[MAX_DRIVERS] = DRIVERS_INIT;

Код менеджера будет использовать drivers[i]->id вместо drivers[i].id.

...