modular approaches are pretty handy in general (portable and clean), so I try to program modules as independent of any other modules as possible. Most of my approaches are based on a struct that describes the module itself. An initialization function sets the primary parameters, afterwards a handler (pointer to desriptive struct) is passed to whatever function inside the module is called.
Right now, I am wondering what the best approach of allocation memory for the struct describing a module may be. If possible, I'd like the following:
- Opaque struct, so the struct may only be altered by the use of provided interface functions
- Multiple instances
- memory allocated by linker
I see the following possibilities, that all conflict with one of my goals:
global declaration
multiple instances, allcoted by linker, but struct is not opaque
(#includes)
module_struct module;
void main(){
module_init(&module);
}
malloc
opaque struct, multiple instances, but allcotion on heap
in module.h:
typedef module_struct Module;
in module.c init function, malloc and return pointer to allocated memory
module_mem = malloc(sizeof(module_struct ));
/* initialize values here */
return module_mem;
in main.c
(#includes)
Module *module;
void main(){
module = module_init();
}
declaration in module
opaque struct, allocated by linker, only a predefined number of instances
keep the whole struct and memory internal to the module and never expose a handler or struct.
(#includes)
void main(){
module_init(_no_param_or_index_if_multiple_instances_possible_);
}
Is there an option to combine these somehow for opaque struct, linker instead of heap allocation and multiple/any number of instances?
solution
as proposed in some answers below, I think the best way is to:
- reserve space for MODULE_MAX_INSTANCE_COUNT modules in the modules source file
- do not define MODULE_MAX_INSTANCE_COUNT in the module itsself
- add an #ifndef MODULE_MAX_INSTANCE_COUNT #error to the modules header file to make sure the modules user is aware of this limitation and defines the maximum number of instances wanted for the application
- on initialization of an instance return either the memory address (*void) of the desricptive struct or the modules index (whatever you like more)
Best Answer
Sure there is. First, however, recognize that the "any number" of instances must be fixed, or at least an upper bound established, at compile time. This is a prerequisite for the instances to be statically allocated (what you're calling "linker allocation"). You might make the number adjustable without source modification by declaring a macro that specifies it.
Then the source file containing the actual struct declaration and all its associated functions also declares an array of instances with internal linkage. It provides either an array, with external linkage, of pointers to the instances or else a function for accessing the various pointers by index. The function variation is a bit more modular:
module.c
I guess you're already familiar with how the header would then declare the struct as an incomplete type and declare all the functions (written in terms of pointers to that type). For example:
module.h
Now
struct module
is opaque in translation units other thanmodule.c
,* and you can access and use up to the number of instances defined at compile time without any dynamic allocation.*Unless you copy its definition, of course. The point is that
module.h
does not do that.