Very often malloc() is absolutely not allowed when programming for embedded systems. Most of the time I'm pretty able to deal with this, but one thing irritates me: it keeps me from using so called 'opaque types' to enable data hiding. Normally I'd do something like this:
// In file module.h
typedef struct handle_t handle_t;
handle_t *create_handle();
void operation_on_handle(handle_t *handle, int an_argument);
void another_operation_on_handle(handle_t *handle, char etcetera);
void close_handle(handle_t *handle);
// In file module.c
struct handle_t {
int foo;
void *something;
int another_implementation_detail;
};
handle_t *create_handle() {
handle_t *handle = malloc(sizeof(struct handle_t));
// other initialization
return handle;
}
There you go: create_handle() performs a malloc() to create an 'instance'. A construction often used to prevent having to malloc() is to change the prototype of create_handle() like this:
void create_handle(handle_t *handle);
And then the caller could create the handle this way:
// In file caller.c
void i_am_the_caller() {
handle_t a_handle; // Allocate a handle on the stack instead of malloc()
create_handle(&a_handle);
// ... a_handle is ready to go!
}
But unfortunately this code is obviously invalid, the size of handle_t isn't known!
I never really found a solution to solve this in a proper way. I'd very like to know if anyone has a proper way of doing this, or maybe a complete different approach to enable data hiding in C (not using static globals in the module.c of course, one must be able to create multiple instances).
You can use the _alloca function. I believe that it's not exactly Standard, but as far as I know, nearly all common compilers implement it. When you use it as a default argument, it allocates off the caller's stack.
// Header
typedef struct {} something;
int get_size();
something* create_something(void* mem);
// Usage
handle* ptr = create_something(_alloca(get_size()); // or define a macro.
// Implementation
int get_size() {
return sizeof(real_handle_type);
}
something* create_something(void* mem) {
real_type* ptr = (real_type_ptr*)mem;
// Fill out real_type
return (something*)mem;
}
You could also use some kind of object pool semi-heap - if you have a maximum number of currently available objects, then you could allocate all memory for them statically, and just bit-shift for which ones are currently in use.
#define MAX_OBJECTS 32
real_type objects[MAX_OBJECTS];
unsigned int in_use; // Make sure this is large enough
something* create_something() {
for(int i = 0; i < MAX_OBJECTS; i++) {
if (!(in_use & (1 << i))) {
in_use &= (1 << i);
return &objects[i];
}
}
return NULL;
}
My bit-shifting is a little off, been a long time since I've done it, but I hope that you get the point.