在C中具有多个灵活数组成员的案例?

时间:2018-11-25 10:35:27

标签: c

问题: 我通过网络接收大小动态的结构,并将其存储在磁盘上。现在,我想提供一些功能来处理这个连续的内存块。

示例:以下内容当然不起作用,只是一个示例:

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;,只需计算实现中的偏移量即可。但是,如果传递了错误的类型,则编译器不会发出警告。

问题:我如何表示这样的数据结构?最常见的方法是什么?

2 个答案:

答案 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_ptrconst_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;
}

希望这对您有帮助...

相关问题