定义为常量的数组成员

Array members defined as constants

我正在尝试实现一个框架,我需要在其中声明(在 .h 文件中)可用 "drivers"(结构变量)的列表,这些列表将在特定的 .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 中实现这种机制吗?

在 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

在 C 中执行此操作的正确方法是立即摆脱所有带有全局变量的 extern-spaghetti。

相反,您可以将结构定义放在 driver.h 中,并在 driver.c 中通过 "constructor":

对其进行初始化
// 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;
}

对于专业代码,这可以通过 here 解释的 "opaque type" 概念进一步改进,以实现私有封装(如果需要,还可以实现多态性)。在这种情况下,结构定义可以(部分)隐藏在 driver.c 中,并且构造函数还处理内存分配。

我想我找到了解决办法。我从 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
};