It's a common problem in embedded projects. You want to hide private data of modules, but you don't want to use dynamic memory allocation.
In the .h file you write the typedef only and in .c file you write the full definition of the struct. In this way you can't statically allocate the struct, because the compiler doesn't know the inner definition. If you want to use static allocation, you need to show the inner definition in the .h file, i.e. define it publicly.
FreeRTOS project uses another strategy. The real private definition is in the .c file, so hiding data. But the .h file has a dummy definition.
--- start of module.h --- typedef struct myclass_s myclass;
typedef struct { uint8_t dummy1; uint16_y dummy2; char dummy3[24]; } static_myclass;
myclass *myclass_create_static(static_myclass *buf, uint8_t age, uint16_t sn, consr char *name);
--- end of module.h ---
--- start of module.c --- struct myclass_s { uint8_t age; uint16_y serial_number; char name[24]; };
myclass *myclass_create_static(static_myclass *buf, uint8_t age, uint16_t sn, consr char *name) { myclass *obj = (myclass *)buf; obj->age = age; obj->serial_number = sn; memcpy(obj->name, name, sizeof(obj->name)); return obj; }
--- end of module.c ---
Do you have better strategies?