簡體   English   中英

在動態分配的結構(數組結構)中分配動態數組

[英]Allocating a dynamic array in a dynamically allocated struct (struct of arrays)

這個問題實際上是關於如何了Python / C API(在使用可變長度類型PyObject_NewVarPyObject_VAR_HEADPyTypeObject.tp_basicsize.tp_itemsize ,但我可以問這個問題,而不與API的細節困擾,只是假設我需要在struct內部使用數組。

我可以通過以下兩種方式之一創建列表數據結構。 (我現在只討論char列表,但這沒關系。)第一個使用指針,並且需要兩個分配 忽略#include和錯誤處理:

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;
}

創建列表的第二種方法使用數組符號和一個分配 (我知道第二個實現有效,因為我已經對其進行了徹底的測試。)

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->data[index]訪問該數組。

我的問題是第二種方法為何有效? 為什么要聲明char data[1]而不是char data[]char data[0]char *datachar data 特別是,我對struct的工作方式的直觀理解是,聲明data的正確方法是完全沒有指針或數組表示法的char data 最后, 在兩個實現中我對basicsizeitemsize計算itemsize正確 特別是,是否對所有機器正確使用了offsetof

更新

顯然,這稱為struct hack :在C99中,您可以使用靈活的數組成員

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

了解到您將在運行時為data malloc足夠的空間。 在C99之前, data[1]聲明很常見。 因此,我的問題是現在為什么要聲明char data[1]char data[]而不是char *datachar data

您聲明char data[1]char data[]而不是char *datachar data是為了使結構直接可序列化和反序列化 在將這些類型的結構寫入磁盤或通過網絡套接字等的情況下,這一點很重要。

例如,需要兩個分配的第一個代碼段。 您的listptr類型不能直接序列化。 即listptr.elems和listptr.data指向的數據不在連續的內存中。 使用通用功能無法從磁盤讀取/寫入此結構。 您需要特定於您的struct listptr類型的自定義函數來執行此操作。 即在序列化時,您必須首先將elems寫入磁盤,然后再寫入數據指針指向的數據。 反序列化時,您必須讀取elems,將適當的空間分配給listptr.data,然后從磁盤讀取數據。

使用靈活的數組成員可以解決此問題,因為listptr.elem和listptr.data駐留在連續的內存空間中。 因此,要對其進行序列化,您只需寫出該結構的總分配大小,然后寫出該結構本身。 在反序列化時,您首先要讀取分配的大小,分配所需的空間,然后將listptr結構讀取到該空間中。

您可能想知道為什么您真的需要此功能,但是它可能是非常寶貴的功能。 考慮異構類型的數據流。 如果您定義了一個標頭,該標頭定義了您擁有的異構類型及其大小,並且在該標頭之前定義了流中的每種類型,則可以非常優雅,高效地進行序列化和反序列化。

我知道選擇char data[1]不是char data[]的唯一原因是,是否要定義一個需要在C99和C ++之間移植的API,因為C ++不支持靈活的數組成員。

另外,想指出的是,在char data[1]您可以執行以下操作以獲得所需的總結構大小:

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

您還問為什么不使用char data代替char data[1]char data[] 雖然從技術上講可以僅使用簡單的舊char data ,但是(IMHO)在道德上應避免使用。 這種方法的兩個主要問題是:

  1. 您需要一個char數組,但是現在您不能直接作為數組訪問data成員。 您需要將指針指向data地址以作為數組進行訪問。

    char * as_array =&listarray.data;

  2. 您的結構定義(以及您的代碼對結構的使用)將完全誤導任何閱讀該代碼的人。 為什么要聲明一個char時,你的真正用意字符數組?

鑒於這兩件事,我不知道為什么有人會使用char data來代替char data[1] 給出替代方案的任何人都不會從中受益。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM