问题: 我通过网络接收大小动态的结构,并将其存储在磁盘上。现在,我想提供一些功能来处理这个连续的内存块。
示例:以下内容当然不起作用,只是一个示例:
typedef struct person {
size_t name_size;
const char name[];
} person;
typedef struct group {
size_t caption_size;
const char caption[];
size_t group_size;
person people[];
} group;
person *group_get_people(const group *g);
const char *person_get_name(const person *p);
size_t person_get_name_size(const person *p);
...
要求:该API应该具有类型,因此很清楚要传递的内容,并且如果传递了错误的类型,则编译器应发出警告。
我尝试过的事情:我目前正在考虑typedef person void;
,只需计算实现中的偏移量即可。但是,如果传递了错误的类型,则编译器不会发出警告。
问题:我如何表示这样的数据结构?最常见的方法是什么?
答案 0 :(得分:2)
您不能在C语言中使用类型安全性表示条件内存布局,但是可以将类型安全的 pointer 包装器作为结构提供,而将指针作为单个成员。像这样:
typedef struct group_ptr {
void* p;
} group_ptr;
typedef struct person_ptr {
void* p;
} person_ptr;
person_ptr group_get_person(group_ptr g, size_t i);
不幸的是,除了添加const_group_ptr
,const_person_ptr
之类的更多类之外,我看不到一种简单的方法来处理常量性。
答案 1 :(得分:1)
我会提出这样的建议(这是伪代码,因为您没有提供太多),但这是主要思想。 基本上,您具有可以与标准指针链接在一起的“经典”结构组和人员(如注释中所述),并且具有用于读取序列化数据的flat_person和flat_group结构。 我在这里几乎没有检查流的长度,请小心,这对于工作代码确实非常必要。
typedef struct person {
size_t name_size;
const char name[];
} flat_person;
typedef struct {
size_t caption_size;
const char caption[];
} flat_group_caption;
typedef struct {
size_t group_size;
flat_person people[];
} flat_group;
group *read_group(const void *stream, size_t len) {
const char *curr_pos_in_stream = stream;
/* considering you have a group struct with 'traditional' linked
* lists to hold several persons */
group *g = malloc(sizeof(*g));
const flat_group_caption *fgc = stream;
/* Check if stream can hold the size of caption and then the
* declared caption itself */
if (len < sizeof(fgc->caption_size)
|| len < sizeof(fgc->caption_size) + fgc->caption_size)
return NULL;
group_add_caption(g, fgc->caption, fgc->caption_size);
curr_pos_in_stream += sizeof(fgc->caption_size) + fgc->caption_size;
len -= sizeof(fgc->caption_size) + fgc->caption_size;
flat_group *fg = (void *)curr_pos_in_stream;
curr_pos_in_stream += sizeof(fg->group_size);
/* FIXME check len is still big enougth */
len -= sizeof(fg->group_size);
for (size_t i = 0; i < fg->group_size; i++) {
const flat_person *fp = (void *)curr_pos_in_stream;
if (len < sizeof(fp->name_size)
|| len < sizeof(fp->name_size) + fp->name_size) {
free(g);
return NULL;
}
person *p = malloc(sizeof(*p));
person_add_name(p, fp->name, fp->name_size);
group_add_person(g, p); // would add the person in the linked list held by group
curr_pos_in_stream += sizeof(fp->name_size) + fp->name_size;
/* FIXME check len is still big enougth */
len -= sizeof(fp->name_size) + fp->name_size;
}
return g;
}
希望这对您有帮助...