Ответ 1
Для каждой структуры данных используйте функцию serialize_X (где X - это имя структуры), которая принимает указатель на X и указатель на непрозрачную структуру буфера и вызывает соответствующие функции сериализации. Вы должны указать некоторые примитивы, такие как serialize_int, которые записывают в буфер и обновляют выходной индекс. Примитивам нужно будет вызвать что-то вроде reserve_space (N), где N - это количество байтов, которое требуется перед записью любых данных. reserve_space() перераспределяет буфер void *, чтобы сделать его как минимум большим, чем текущий размер плюс N байтов. Чтобы сделать это возможным, структура буфера должна содержать указатель на фактические данные, индекс для записи следующего байта (индекс вывода) и размер, который выделяется для данных. В этой системе все ваши функции serialize_X должны быть довольно простыми, например:
struct X {
int n, m;
char *string;
}
void serialize_X(struct X *x, struct Buffer *output) {
serialize_int(x->n, output);
serialize_int(x->m, output);
serialize_string(x->string, output);
}
И код рамки будет выглядеть примерно так:
#define INITIAL_SIZE 32
struct Buffer {
void *data;
int next;
size_t size;
}
struct Buffer *new_buffer() {
struct Buffer *b = malloc(sizeof(Buffer));
b->data = malloc(INITIAL_SIZE);
b->size = INITIAL_SIZE;
b->next = 0;
return b;
}
void reserve_space(Buffer *b, size_t bytes) {
if((b->next + bytes) > b->size) {
/* double size to enforce O(lg N) reallocs */
b->data = realloc(b->data, b->size * 2);
b->size *= 2;
}
}
Из этого, должно быть довольно просто реализовать все функции serialize_(), которые вам нужны.
EDIT: Например:
void serialize_int(int x, Buffer *b) {
/* assume int == long; how can this be done better? */
x = htonl(x);
reserve_space(b, sizeof(int));
memcpy(((char *)b->data) + b->next, &x, sizeof(int));
b->next += sizeof(int);
}
EDIT: Также обратите внимание, что у моего кода есть некоторые потенциальные ошибки. Размер массива буфера хранится в size_t, но индекс является int (я не уверен, что size_t считается разумным типом для индекса). Кроме того, нет никаких предустановок для обработки ошибок и нет функции освобождения буфера после того, как вы закончите, поэтому вам придется сделать это самостоятельно. Я просто продемонстрировал базовую архитектуру, которую я бы использовал.