How can I "pack" and "write" a struct to a file using C so that:
struct a { uint64_t a; char* b; uint16_t c; } a; a b; b.a = 3; b.b = "Hello"; b.c = 4;
gets written to the file as
00 00 00 00 00 00 00 03 48 65 6c 6c 6f 00 00 04
How can I "pack" and "write" a struct to a file using C so that:
struct a { uint64_t a; char* b; uint16_t c; } a; a b; b.a = 3; b.b = "Hello"; b.c = 4;
gets written to the file as
00 00 00 00 00 00 00 03 48 65 6c 6c 6f 00 00 04
In C, you'll have to code a function to do this for you. You can't just blat the structure out to disk because b
is a pointer that makes no sense without the backing string. And, unless you know (and can control) how your compiler packs its structures, you're better off with a utility function anyway, even without pointers.
And, as if that wasn't enough, you should output the length of the string as well so you know how many bytes to read back.
You'll be looking for something like:
int better_than_blat (FILE *f, struct a *x) {
size_t len = strlen (x->b);
if (fwrite (&(x->a), sizeof(long), 1, f) != 1) return -1;
if (fwrite (&len, sizeof(size_t), 1, f) != 1) return -1;
if (fwrite (x->b, len, 1, f) != 1) return -1;
if (fwrite (&(x->c), sizeof(short), 1, f) != 1) return -1;
return 0;
}
int better_than_unblat (FILE *f, struct a *x) {
size_t len;
if (fread (&(x->a), sizeof(long), 1, f) != 1) return -1;
if (fread (&len, sizeof(size_t), 1, f) != 1) return -1;
x->b = malloc (len + 1);
if (x->b == NULL) return -1;
memset (x->b, 0, len + 1);
if (fread (x->b, len, 1, f) != 1) return -1;
if (fread (&(x->c), sizeof(short), 1, f) != 1) return -1;
return 0;
}
you must write your own way to serialize this data; the compiler won't hand you a built-in way to deal with the string. There are serialization libraries out there but I don't know any for straight C.
But, consider using a more structured method for serializing data, such as json or xml. Even an INI file is better than raw binary dump. Reasons for this are:
Will the following help?
struct buffer {
char bytes[1000];
int nbytes;
};
struct buffer *new_buffer(){
struct buffer b = (struct buffer*) malloc(sizeof(struct buffer));
b->nbytes = 0;
return b;
}
void append_long(struct buffer *b, long *l){
memcpy(b->bytes + b->nbytes, l);
b->nbytes += sizeof(*l);
}
// ...and so on for other types
void fwrite_buffer(FILE *fp, struct buffer *b){
fwrite(b->bytes, sizeof(*b), 1, fp);
}
Usage:
struct buffer *buf = new_buffer();
struct a b;
b.a = 3;
b.b = "Hello";
b.c = 4;
append_long(buf, &(b.a));
append_pointer(buf, &(b.b));
append_short(buf, &(b.b));
fwrite_buffer(fp, buf);
You can safely pack your structure into byte array, if you will not use pointers in it and will explicitly define packing alignment.
For example (gcc):
struct a { long a; char b[256]; short c; } __attribute__((__packed__)); int size = sizeof(a); void* buffer = malloc(size); memcpy(buffer, (void*)a, size);