I'm trying to create an interface definition with different implementations. The interface is defined as a typedef struct that contains some function pointers and a void* member which is intended to be a pointer to an implementation specific struct. The idea is that this struct will hold configuration data to initialize a particular implementation and that struct is different for various implementations.
The issue is dereferencing the inner struct because the compiler thinks it's a void* type.
Here is a simplified snippet of my basic framework:
// interface.h
typedef struct {
void* cfg;
void (*write)(int val);
}Dev;
// implementation.h
#include "interface.h"
typedef struct fooInitCfg {
int a;
int b;
}fooInitCfg;
fooInitCfg* foo_cfg();
void foo_init(Dev* self, fooInitCfg* cfg);
// implementation.c
#include "implementation.h"
// Implement foo_write() ...
Dev* foo_create() { return malloc(sizeof(Dev)); }
void foo_free(Dev* self) { free(self); }
void foo_init(Dev* self, fooInitCfg* cfg)
{
self->cfg = cfg;
self->write = foo_write;
printf("%s::%d:: Init values: %d, %d\n\r", __func__, __LINE__, self->cfg->a, self->cfg->b);
}
fooInitCfg* foo_cfg(int a, int b)
{
fooInitCfg* cfg = malloc(sizeof(fooInitCfg));
cfg->a = a;
cfg->b = b;
return cfg;
}
// main.c
Dev* f1 = foo_create();
fooInitCfg init = {5, 100};
fooInitCfg* f1_init = foo_cfg(5, 100);
foo_init(f1, f1_init);
This is the compiler error that I get:
gcc -std=c99 -g -Wall -c foo.c -o foo.o
foo.c: In function ‘foo_init’:
foo.c:25:77: warning: dereferencing ‘void *’ pointer
25 | printf("%s::%d:: Init values: %d, %d\n\r", __func__, __LINE__, self->cfg->a, self->cfg->b);
| ^~
foo.c:25:77: error: request for member ‘a’ in something not a structure or union
I've tried a bunch of things to fix this but I can't quite figure out how to make it work. I tried a flexible array member but that seems like it needs a known type in the interface and not void*.
The type of cfg needs to be given explicitly, otherwise, the GCC compiler considers it as (void*), upon the definition in type Dev.
The following code snippet modified can pass the GCC compiler.
printf("%s::%d:: Init values: %d, %d\n\r", __func__, __LINE__,
((fooInitCfg*)(self->cfg))->a,
((fooInitCfg*)(self->cfg))->b);
The result runned is as the follows.
foo_init::24:: Init values: 5, 100