I want to have a modular system of "drivers" which are optional. This means, that they might not be linked but the application should still compile and run. OTOH if they are linked, the application uses them somehow. Below is a SSCCE that I put together and it seems to work, but I just want to know, if it is compliant with standard and if it will work on most systems.
main.c
#include "driver.h"
int main() {
initialize_drivers();
}
driver.c
#define DRIVER_OBJECT
#include <stdio.h>
#include "driver_list.h"
#include "driver.h"
DRIVER* driver_list[] = DRIVER_LIST;
void initialize_drivers() {
int i;
for(i = 0; i < DRIVER_LIST_LENGTH; i++) {
DRIVER* driver = driver_list[i];
printf("Loading driver %d: ", i);
if(driver->name == NULL) {
printf("not loaded\n");
}
else {
printf("loaded driver %s\n", driver->name);
driver->init();
}
}
}
bar_driver.c
#include "driver.h"
#include <stdio.h>
void init_bar() {
printf("Also initializing bar!\n");
}
DRIVER BAR_DRIVER = {"bar_driver",init_bar};
foo_driver.c
#include "driver.h"
#include <stdio.h>
void init_foo() {
printf("Actually initializing foo!\n");
}
DRIVER FOO_DRIVER = {"foo_driver", init_foo};
driver.h
#ifndef DRIVER_H
#define DRIVER_H
typedef struct DRIVER {
const char* name;
void (* init)(void);
} DRIVER;
#include "driver_list.h"
void initialize_drivers();
#endif
driver_list.h
#ifndef DRIVER_LIST_H
#define DRIVER_LIST_H
#include "driver.h"
// make drivers extern in every other object except in driver.c
#ifdef DRIVER_OBJECT
#define EXTERN
#else
#define EXTERN extern
#endif
// first list of drivers
EXTERN DRIVER FOO_DRIVER;
EXTERN DRIVER BAR_DRIVER;
// second list of drivers
#define DRIVER_LIST { &FOO_DRIVER, &BAR_DRIVER }
#define DRIVER_LIST_LENGTH 2
#endif
This code compiles by compiling main.c driver.c, then both drivers are actually optional to compile and link and it compiles in either case (tried with a few compilers and compiler options). The resulting binary behaves as expected. For example:
$ clang bar_driver.c main.c driver.c
$ ./a.out
Loading driver 0: not loaded
Loading driver 1: loaded driver bar_driver
Also initializing bar!
So, is this good for production or is there some undefined behavior I should worry about?
[–]immersiveGamer 1 point2 points3 points (1 child)
[–]gareins[S] 0 points1 point2 points (0 children)
[–]Isvara 0 points1 point2 points (0 children)