I just want to parse some data that can be present in one of two types. First one is
struct typeA {
int id,
char name[16],
int value1,
int value2,
int value3,
int value4
} __attribute__ ((packed));
second possibility is that the data has a form with double name length
struct typeB {
int id,
char name[32],
int value1,
int value2,
int value3,
int value4
} __attribute__ ((packed));
so far so good. Now I have two functions that parse these two
int parse_typeA(struct typeA *x){ /* do some stuff */ }
int parse_typeB(struct typeB *x){ /* do some stuff */ }
Now this is obviously impractical if you have more types. How can I realize the parsing of both types using one single function and an additional parameter like
int parse_any_type(void *x, int type){
/*
* WHAT TO DO HERE ??
*
* The following doesn't work
*
* if(type == 1)
* struct typeA *a = (struct typeA *)x;
* else
* struct typeB *a = (struct typeB *)x;
*/
printf("%i\n", a->id);
printf("%s\n", a->name);
printf("%i\n", a->value1);
printf("%i\n", a->value2);
printf("%i\n", a->value3);
printf("%i\n", a->value4);
}
Anyone any idea?
It depends on how general your solution must be. As other answers have identified, the two example structures are extremely similar, and therefore can be managed relatively easily (though deciding how to determine the end of the character string presents some problems).
If you need a more general system, you’ll probably need to look at some sort of ‘structure descriptor’ string, which you pass to the converter, or possibly a ‘structure descriptor array’.
For example, the strings might be:
You then have to deal with some alignment and padding issues, but (as long as you get the descriptor strings correct) you can write a routine to handle that lot (packed or unpacked).
Using ‘descriptors’, you’d probably be dealing with one of the less well known macros in C, the
offsetofmacro defined in<stddef.h>. You’d create a descriptor type such as:You can then pass the appropriate type descriptor array (and the size of that array) to the function, along with the pointer to where the data is to be stored.
Instead of using an enumeration, you might use a function pointer type which points to the correct converter.
Another alternative is that you simply deal with each type with an appropriate function which calls other simpler functions to handle each piece of the structure.
Your examples have not clearly identified where the data comes from, as opposed to where it is to be stored. This may not matter, but will affect the solution. Given no arguments, it might be reasonable to expect the data to be read from standard input. Alternatively, you might have a string containing the data to be parsed, possibly with a length, too; these would be arguments to the function.
Your examples have not illustrated error handling; how will the calling code know whether the conversion was successful or not.
If done correctly, the same description mechanism can be used for both the parsing and the printing mechanisms – your
parse_any_type()function looks more like a printing function.See Also
offsetof()on a struct?__builtin_offsetof()operator?