我正在尝试实现一个框架,在该框架中,我需要声明(在.h文件中)可用的“驱动程序”(结构变量)列表,这些列表将在特定的.c模块中定义。由于列表将来可能会增加,因此我希望将其全部放在.h文件中的一个位置,以使其易于扩展。
例如让我们有“ driver.h”
public async Task<ActionResult> AddDeviceAsync()
{
Device device;
try
{
connectionString = ConfigurationManager.AppSettings["DefaultIoTHubConnection"];
registryManager = RegistryManager.CreateFromConnectionString(connectionString);
List<string> collection = new List<string>();
for (int i = 0; i < 4; i++)
{
collection.Add("dummy_device_" + i);
}
foreach (var deviceId in collection)
{
try
{
// register device into IoT hub
device = await registryManager.AddDeviceAsync(new Device(deviceId)); // getting exception here
然后将在专用模块中定义特定的驱动程序(driver1,driver2,driver3)。 driver1.c,driver2.c ..等...
但是我想有一个模块,例如manager.c,我想定义在driver.h中声明的可用驱动程序的数组,以便能够迭代该数组并获取用于框架其他部分的驱动程序。
因此在manager.c中,我将需要以下内容:
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
但是显然,它不是以这种方式编译的。 主要思想是仅在将来需要添加其他驱动程序的声明时才编辑driver.h,然后仅在专用模块中实现它,而无需编辑例如manager.c或框架的其他部分。 你有什么想法,如何在c中实现这样的机制?
答案 0 :(得分:1)
在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
。
答案 1 :(得分:1)
在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;
}
对于专业代码,可以使用here中所述的“不透明类型”概念进一步加以改进,以实现私有封装(以及必要时的多态性)。在这种情况下,结构定义可以(部分)隐藏在driver.c中,并且构造函数还可以处理内存分配。
答案 2 :(得分:1)
我想我找到了解决方案。我从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
};