开发者

Writing 'packed' structs to file using C

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:

  • easier to debug
  • more forward compatible
  • less rigid / error-prone
  • if you use an existing library, then you reap the rewards of the community that goes with it.
  • an existing library is likely to support features that you will later scratch your head over like arrays
  • better cross platform compatibility.


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);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜