Search code examples
cstructmalloc

Allocate memory for interface struct with void* members in C


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*.


Solution

  • 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