pedroke
pedroke

Reputation: 31

Array members defined as constants

I'm trying to implement a framework, where I would need to declare (in .h file) the list of available "drivers" (struct variables) which would be defined in specific .c modules. As the list would probably grow in the future I would like to have it all in one place in the .h file to keep it easily extensible.

E.g. let's have "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

Then the specific drivers (driver1, driver2, driver3) would be defined in dedicated modules.. e.g. driver1.c, driver2.c .. etc...

But then I would like to have a module e.g. manager.c where I would like to define the array of available drivers as declared in driver.h so that I'm able to iterate the array and get the drivers for usage in other parts of the framework..

So in manager.c I would need something like:

driver_t drivers[MAX_DRIVERS] = {DRIVERS}

But obviously it does not compile this way.. The main idea is to edit only driver.h when I need to add declaration for additional driver in the future and then just implement it in dedicated module, whithout the necessity to edit e.g. manager.c or other parts of the framework.. Do you have any idea, how to implement such mechanism in c?

Upvotes: 2

Views: 100

Answers (3)

pedroke
pedroke

Reputation: 31

I think I found a solution. I took the inspiration from the rtl_433 project https://github.com/merbanan/rtl_433/blob/master/include/rtl_433_devices.h where they defined something similar for the devices declarations.

So it should be in header file:

/* driver.h */
#define DRIVERS \
    DECL(driver1) \
    DECL(driver2) 


#define DECL(name) extern driver_t name;
    DRIVERS
#undef DECL

And then in module:

/* driver.c */

driver_t* drivers[] = {  
#define DECL(name) &name,
    DRIVERS
#undef DECL
};

Upvotes: 1

Lundin
Lundin

Reputation: 213721

The proper way to do this in C is to immediately get rid of all extern-spaghetti with globals.

Instead you could put your struct definition inside driver.h and in driver.c initialize it through a "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;
}

For professional code, this can be further improved with the concept of "opaque type" as explained here, to achieve private encapsulation (and if needed polymorphism). In which case the struct definition can be (partially) hidden in driver.c and the constructor also handles memory allocation.

Upvotes: 1

ReAl
ReAl

Reputation: 1301

In C you can't initialize an array with copies of some objects (in C++ can but it is not good practice because they are copies and will be changed independently with original objects).

drivers array should contain pointers to original objects. I suggest something like

/* 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;

Manager code will use drivers[i]->id instead of drivers[i].id.

Upvotes: 1

Related Questions