分配一个动态数组在一个动态分配的结构(阵列结构) [英] Allocating a dynamic array in a dynamically allocated struct (struct of arrays)

查看:175
本文介绍了分配一个动态数组在一个动态分配的结构(阵列结构)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这问题实际上是关于如何了Python / C API中使用变长类型(的 PyObject_NewVar ,的 PyObject_VAR_HEAD ,的 PyTypeObject.tp_basicsize .tp_itemsize ,但我可以问这个问题,而不与API的细节困扰。只是假设我需要使用在结构

This question is really about how to use variable-length types in the Python/C API (PyObject_NewVar, PyObject_VAR_HEAD, PyTypeObject.tp_basicsize and .tp_itemsize , but I can ask this question without bothering with the details of the API. Just assume I need to use an array inside a struct.

我可以创建以两种方式之一的列表的数据结构。 (我就谈谈字符名单了,但没关系。)第一个使用指针,并要求两笔拨款。忽略的#include 和错误处理:

I can create a list data structure in one of two ways. (I'll just talk about char lists for now, but it doesn't matter.) The first uses a pointer and requires two allocations. Ignoring #includes and error handling:

struct listptr {
    size_t elems;
    char *data;
};
struct listptr *listptr_new(size_t elems) {
    size_t basicsize = sizeof(struct listptr), itemsize = sizeof(char);
    struct listptr *lp;
    lp = malloc(basicsize);
    lp->elems = elems;
    lp->data = malloc(elems * itemsize);
    return lp;
}

要创建一个列表的第二种​​方法使用数组符号和一个分配即可。 (我知道本次执行工作,因为我已经测试过它彻底pretty。)

The second way to create a list uses array notation and one allocation. (I know this second implementation works because I've tested it pretty thoroughly.)

struct listarray {
    size_t elems;
    char data[1];
};
struct listarray *listarray_new(size_t elems) {
    size_t basicsize = offsetof(struct listarray, data), itemsize = sizeof(char);
    struct listarray *la;
    la = malloc(basicsize + elems * itemsize);
    la->elems = elems;
    return lp;
}

在这两种情况下,你再使用 LP-方式>数据[指数] 来访问数组

In both cases, you then use lp->data[index] to access the array.

我的问题是,为什么第二种方法工作?你为什么声明 char数据[1] 而不是任何的 char数据[] CHAR数据[0] 的char *数据 char数据?尤其是我的结构的工作是如何正确的方式来声明数据直观的理解是 char数据没有指针或数组符号的。最后,是我的 basicsize 的计算,并在这两个实施 itemsize 正确?尤其是这种使用的offsetof 保证所有机器是正确的?

My question is why does the second method work? Why do you declare char data[1] instead of any of char data[], char data[0], char *data, or char data? In particular, my intuitive understanding of how structs work is that the correct way to declare data is char data with no pointer or array notation at all. Finally, are my calculations of basicsize and itemsize correct in both implementations? In particular, is this use of offsetof guaranteed to be correct for all machines?

显然,这就是所谓的结构黑客:在C99,你可以使用<一个href=\"https://www.securecoding.cert.org/confluence/display/sec$c$c/void+MEMxx-C.+Understand+how+flexible+array+members+are+to+be+used\"相对=nofollow>灵活的数组成员:

Apparently this is called a struct hack: In C99, you can use a flexible array member:

struct listarray2 {
    size_t elems;
    char data[];
}

与理解,你会的malloc 足够的空间,在运行时数据。 C99的之前的数据[1] 声明是共同的。所以我的问题是现在的为什么声明 char数据[1] char数据[] 而不是的char *数据 char数据

with the understanding that you'll malloc enough space for data at runtime. Before C99, the data[1] declaration was common. So my question now is why declare char data[1] or char data[] instead of char *data or char data?

推荐答案

你声明 char数据[1] char数据的原因[] 而不是的char *数据 char数据是保持结构的直接序列化和deserializable 。这在你编写这类结构的磁盘或网络套接字等案件的重要。

The reason you'd declare char data[1] or char data[] instead of char *data or char data is to keep your structure directly serializable and deserializable. This is important in cases where you'll be writing these sorts of structures to disk or over a network socket, etc.

举个例子,需要两个分配你的第一个code片段。你的listptr类型不是直接序列化。即listptr.elems和由listptr.data指向的数据不是在一个连续的一块存储器。没有办法来读/与通用功能写这个结构向/从磁盘。您需要自定义函数特定于你的结构listptr 类型做到这一点。即在连载你必须先写 elems 到磁盘,然后写入数据由数据指针指向。在反序列化,你不得不读elems,分配相应的空间来listptr.data,然后从硬盘读取数据。

Take for example your first code snippet that requires two allocations. Your listptr type is not directly serializable. i.e. listptr.elems and the data pointed to by listptr.data are not in a contiguous piece of memory. There is no way to read/write this structure to/from disk with a generic function. You need a custom function that is specific to your struct listptr type to do it. i.e. On serialize you'd have to first write elems to disk, and then write the data pointed to by the data pointer. On deserialization you'd have to read elems, allocate the appropriate space to listptr.data and then read the data from disk.

使用柔性阵列构件因为listptr.elem和listptr.data驻留在一个连续的存储器空间来解决这个问题。因此,要序列化可以简单的写出来的结构,然后对结构本身分配的总大小。在反序列化你再先阅读分配的大小,分配所需的空间,然后读你listptr结构成的空间。

Using a flexible array member solves this problem because listptr.elem and the listptr.data reside in a contiguous memory space. So to serialize it you can simply write out the total allocated size for the structure and then the structure itself. On deserialize you then first read the allocated size, allocate the needed space and then read your listptr struct into that space.

您可能会想知道为什么你会永远真的需要这一点,但它可以是一个非常宝贵的特性。考虑异构类型的数据流。只要你定义它定义你有哪些异型,其大小和precede每种流与该头的报头,可以统称序列化和反序列化数据流非常优雅和高效。

You may wonder why you'd ever really need this, but it can be an invaluable feature. Consider a data stream of heterogeneous types. Provided you define a header that defines the which heterogeneous type you have and its size and precede each type in the stream with this header, you can generically serialize and deserialize data stream very elegantly and efficiently.

我知道的唯一之所以选择 char数据[1] char数据[] 是,如果你正在定义一个需要C99和C ++之间移植的API,因为C ++不具备灵活的阵列成员的支持。

The only reason I know of for choosing char data[1] over char data[] is if you are defining an API that needs to be portable between C99 and C++ since C++ does not have support for flexible array members.

另外,要指出的是,在 char数据[1] 您可以执行以下操作来获得所需的总结构尺寸:

Also, wanted to point out that in the char data[1] you can do the following to get the total needed structure size:

size_t totalsize = offsetof(struct listarray, data[elems]);

您还想问,为什么你不使用 char数据而不是 char数据[1] char数据[] 。虽然技术上可以使用只是普通的老 char数据,这将是(恕我直言)道德避之唯恐不及。这种方法的两个主要问题是:

You also ask why you wouldn't use char data instead of char data[1] or char data[]. While technically possible to use just plain old char data, it would be (IMHO) morally shunned. The two main issues with this approach are:


  1. 您想字符数组,但现在你不能作为数组直接访问数据成员。你需要一个指针指向 数据访问它作为一个数组的地址。即。

  1. You wanted an array of chars, but now you can't access the data member directly as an array. You need to point a pointer to the address of data to access it as an array. i.e.

的char * as_array =安培; listarray.data;

char *as_array = &listarray.data;

您结构定义(和你的code的使用结构)将完全误导任何人读取code。为什么要声明一个字符当你真正的意思字符数组?

Your structure definition (and your code's use of the structure) would be totally misleading to anyone reading the code. Why declare a single char when you really meant an array of char?

由于这两件事情,我不知道为什么有人会赞成 char数据[1] char数据 $ C>。它只是不利于任何人给予的替代品。

Given these two things, I don't know why anyone would use char data in favor of char data[1]. It just doesn't benefit anyone given the alternatives.

这篇关于分配一个动态数组在一个动态分配的结构(阵列结构)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆