copx said:
I want to save a struct to disk.... as plain text.
At the moment I do it with a function that just
writes the data using fprintf. I mean like this:
fprintf(fp, "%d %d", my_struct.a, my_struct.b)
This way I have to write another "serializing"
function for every new kind of struct I want
to write, though. Is there a way to write
functions that can write/read any struct
to/from plain text format in a portable way?
Such a serializing function would need to know the type and location
of each structure member. If you store this information once for every
structure, you can pass it as an additional argument to a structure
serializing function. The program below should give you some ideas.
Martin
#include <stddef.h>
#include <stdio.h>
/* Structure that will be serialized. */
struct foo {
int a;
unsigned long b;
double c;
};
/* Information about a structure member. */
struct member_info {
enum {NIL, TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_DOUBLE} type;
size_t offset;
};
/* Information about the members of struct foo. */
const struct member_info foo_info [] = {
{TYPE_INT, offsetof (struct foo, a)},
{TYPE_ULONG, offsetof (struct foo, b)},
{TYPE_DOUBLE, offsetof (struct foo, c)},
{NIL, 0}
};
void serialize (const void *const data, const struct member_info *info)
{
while (1)
{
switch (info->type)
{
case TYPE_INT:
printf ("%d", *(int *)((char *)data + info->offset));
break;
case TYPE_UINT:
printf ("%u", *(unsigned int *)((char *)data + info->offset));
break;
case TYPE_LONG:
printf ("%ld", *(long *)((char *)data + info->offset));
break;
case TYPE_ULONG:
printf ("%lu", *(unsigned long *)((char *)data + info->offset));
break;
case TYPE_DOUBLE:
printf ("%f", *(double *)((char *)data + info->offset));
break;
}
if ((++info)->type == NIL)
{
putchar ('\n');
break;
}
else
putchar (' ');
}
}
int main (void)
{
struct foo myfoo = {42, 2004, 3.1415926536};
serialize (&myfoo, foo_info);
return 0;
}