数组成员定义为常量

时间:2018-10-16 12:40:59

标签: c frameworks initialization header-files

我正在尝试实现一个框架,在该框架中,我需要声明(在.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中实现这样的机制?

3 个答案:

答案 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
};