If you do not have the type of the struct being passed (like your void* suggests), basically you are doomed. They are but a bunch of memory with a beginning address.
What you can do is have several functions like the update_fields you suggested and somehow call the right one depending on the type of structure (that is easy and can be quite hidden in a macro to avoid syntaxic noise).
Doing so you get code as below:
#include <stdio.h>
#include <string.h>
typedef struct {
char street[10];
char city[10];
char lat[10];
char lon[10];
} ADDR_A;
typedef struct {
char street[10];
char city[10];
char zip[10];
char country[10];
} ADDR_B;
#define UPDATEFIELDS(type, value) updateFields_##type(value)
static void updateFields_ADDR_A(ADDR_A *myStruct ) {
strcpy(myStruct->street, "abc" );
strcpy(myStruct->city, "def" );
}
static void updateFields_ADDR_B(ADDR_B *myStruct ) {
strcpy(myStruct->street, "abc" );
strcpy(myStruct->city, "def" );
}
int main(){
ADDR_A a;
ADDR_B b;
updateFields_ADDR_A(&a);
updateFields_ADDR_B(&b);
UPDATEFIELDS(ADDR_A, &a);
printf("%s\n", a.city);
printf("%s\n", b.city);
}
Notice that you obviously should not write actual field change code in updateFields_XXX functions but just use that code as the wrapper to get the right offset to inner fields.
I you also want to have code locality you can use macro again,
#define COMMONBODY strcpy(myStruct->street, "abc" );\
strcpy(myStruct->city, "def" );
static void updateFields_ADDR_A(ADDR_A *myStruct ) {
COMMON_BODY
}
static void updateFields_ADDR_B(ADDR_B *myStruct ) {
COMMON_BODY
}
or even put common code in a separate file and include it two times (quite unusual, but working file)
static void updateFields_ADDR_A(ADDR_A *myStruct ) {
#include "commonbody.c"
}
static void updateFields_ADDR_B(ADDR_B *myStruct ) {
#include "commonbody.c"
}
It is also nearly possible (but not quite as long as I know) to do it using typeof operator except the name mangling part.
If your structure are of different size we could even use only one updateFields function (with void*) that takes in the size of the structure as second parameter and use it to automagically cast to the right type. It's quite dirty but possible [please comment if someone wants to see that solution developped].
You can also use an union. Common fields will be accessible using any of the union member if there is a common prefix (but I understand it is not so). You have to understand that defining such union does not change anything to the existing data structure. That's basically defining a type either ADDR_A or ADDR_B than can be referenced using a pointer.
typedef union {
ADDR_A a;
ADDR_B b;
} ADDR_A_or_B;
If there is common prefix you can set these variable using any accessor field:
static void updateFields(ADDR_A_or_B *myStruct ) {
strcpy( myStruct->a.street, someStreeValueFromSomewhereElse);
strcpy( myStruct->a.city, someCityValueFromSomewhereElse);
}
You just need to cast when calling:
ADDR_A a;
updateFields((ADDR_A_or_B *)&a);
ADDR_B b;
updateFields((ADDR_A_or_B *)&b);