在 C 中跨多个源文件创建调度 table 注册函数

Create dispatch table registering functions across multiple source files in C

How can I implement a dynamic dispatch table in C

它与链接的问题本质上是同一个问题,所以...

As your Strategy.c obviously already knows about the strategy instances by name (#include "XYstrategy.h") you could go the whole mile and use the header files instead of the implementation files to communicate your strategy to the central dispatcher:

这与问题的明确意图相悖。这是他如何静态地执行此操作的示例,但希望让模块在编译时动态注册自己。

让我试着提供一个我为自己的目的而苦苦挣扎的例子...

我有一个微控制器,我想用它来读取各种报告温度 and/or 湿度的传感器。我有一个中央核心程序,负责格式化 returned 数据并将其提交到 Web 服务器,并记录在 RRD 中。

我不想构建一个包含每种传感器类型的所有不同功能的大型单片程序,而是希望能够在微控制器上加载的软件中构建一个特定的子集,该子集对应于安装在微控制器上的传感器特定控制器。

为此,我希望能够为具有三个功能的每个传感器编写一个通用驱动程序:

bool _sensor_startup();
bool _read_sensor(float *temp, float *humidity, uint8_t max_count, uint8_t *count);
bool _sensor_shutdown();

sensor_startup 函数将负责为传感器供电,确保它们已正确配置并处于准备好调用 read_sensor 的状态。如果此过程因任何原因失败,它 returns false,否则,它 returns true.

read_sensor 函数将导致最多读取 max_count 个传感器,并将它们的结果存储在分别由 temphumidity 指向的数组中。读取的传感器数量将存储在 count.

sensor_shutdown 函数将执行任何必要的内务处理,return 传感器和支持电子设备进入最低功耗配置。

每个都包含在一个单独的 .c 文件中,该文件可能有一个相应的 .h 文件来定义相关常量、调用相关库等。

我想要一个主 Sensor.h 文件,它包含在 .c 或 .h 文件中,它定义了:

typedef struct { startup_func, read_func, shutdown_func } sensor_driver_entry;

extern sensor_driver_entry sensor_table[];

然后我希望每个驱动程序文件都能够在编译时使用宏(或函数)在 sensor_table 的下一个开放槽中注册特定于类型的函数。

我希望传感器 table 在 Sensor.c 的全局命名空间中声明为:

sensor_driver_entry sensor_table[MAX_SENSOR_TYPES];

MAX_SENSOR_TYPES 将在 Sensor.h 中定义,反映可以选择的最大可能驱动程序数)。

这可能吗?如果是这样,有人可以提供一个句法示例吗?在这种特定情况下,我在 Particle Dev 环境中为 Particle Photon 编码,但如果我可以使代码也 portable 到 Arduino IDE 以与它一起使用,我会很高兴ESP8266板也是。

一种可能性是使用构造函数。下面是一个简单的例子,两个驱动分别注册了他们的函数。

如果应用程序是使用两个驱动程序 (gcc main.c driver1.c driver2.c) 编译的,则输出显示两个已注册的驱动程序函数:

driver1_init
driver2_init
driver1_func
driver2_func

如果在 (gcc main.c driver1.c) 中仅编译了第一个驱动程序,则输出仅显示已注册该驱动程序的功能:

driver1_init
driver1_func

driver.h

typedef void (*driver_func_t)(void);
typedef struct { driver_func_t func; } driver_entry_t;

#define MAX_TYPES 10
extern driver_entry_t driver_table[MAX_TYPES];
extern unsigned int num_driver_entries;

main.c

#include <stdio.h>
#include "driver.h"

driver_entry_t driver_table[MAX_TYPES];
unsigned int num_driver_entries;

int main (void)
{
    unsigned int ix;

    for (ix = 0; ix < num_driver_entries; ix++) {
        driver_table[ix].func();
    }

    return 0;
}

driver1.c

#include <stdio.h>
#include "driver.h"

void driver1_func (void)
{
    printf("%s\n", __FUNCTION__);
}

void driver1_init (void) __attribute__ ((constructor));
void driver1_init (void)
{
    printf("%s\n", __FUNCTION__);
    driver_table[num_driver_entries++].func = driver1_func;
}

driver2.c

#include <stdio.h>
#include "driver.h"

void driver2_func (void)
{
    printf("%s\n", __FUNCTION__);
}

void driver2_init (void) __attribute__ ((constructor));
void driver2_init (void)
{
    printf("%s\n", __FUNCTION__);
    driver_table[num_driver_entries++].func = driver2_func;
}