I suggest using an intermediate structure. For instance:
typedef struct { int version; void* data; } foo_interface; typedef struct { char* x; int y; } foo; typedef struct { char* x; int y; int z; } foo_2;
In my version of library 2, I exported the following function by name:
foo_interface* getFooObject() { foo_interface* objectWrapper = malloc(sizeof(foo_interface)); foo_2* realObject = malloc(sizeof(foo_2)); realObject.x = malloc(1 * sizeof(char)); realObject.y = 2; realObject.z = 3; objectWrapper.version = 2; objectWrapper.data = (void*)realObject; return (objectWrapper); }
Then in the main application I would do:
int main(int ac, char **av) { foo_interface* objectWrapper = myLibrary.getFooObject(); switch (objectWrapper->version) { case 1: foo* realObject = (foo*)(objectWrapper ->data); break; case 2: foo_2* realObject = (foo_2*)(objectWrapper ->data); break; default: printf("Unknown foo version!"); break; } return (0); }
As usual, security checks (for memory allocation, for example) are not included for readability of the code.
In addition, I would use stdint.h to ensure binary data files are compatible (to make sure that the sizes of int , double , char* etc. are the same for different architectures). For example, instead of int I would use int32_t .
HRold source share