簡體   English   中英

C ++ struct alignment和STL向量

[英]C++ struct alignment and STL vectors

我有一個672字節長的遺留數據結構。 這些結構按順序存儲在文件中,我需要讀取它們。

雖然我可以一個一個地閱讀它們,但這樣做會很好:

// I know in advance how many structs to read in
vector<MyStruct> bunchOfStructs;
bunchOfStructs.resize(numberOfStructs);

ifstream ifs;
ifs.open("file.dat");
if (ifs) {
    ifs.read(&bunchOfStructs[0], sizeof(MyStruct) * numberOfStructs);
}

這是有效的,但我認為它只能起作用,因為數據結構大小恰好可以被編譯器的結構對齊填充整除。 我懷疑它會破壞其他編譯器或平台。

另一種方法是使用for循環一次一個地讀取每個結構。

問題 - >我什么時候需要關注數據對齊? 向量中動態分配的內存是否使用填充或STL是否保證元素是連續的?

該標准要求您能夠創建結構類型的數組。 執行此操作時,陣列必須是連續的。 這意味着,無論為結構分配什么大小,它都必須是允許您創建它們的數組的大小。 為了確保這一點,編譯器可以在結構內部分配額外的空間,但不能在結構之間需要任何額外的空間。

vector的數據空間(通常)使用::operator new (通過Allocator類)分配,並且需要::operator new來分配正確對齊的空間以存儲任何類型。

您可以提供自己的分配器和/或重載::operator new - 但如果這樣做,您的版本仍然需要滿足相同的要求,因此在這方面不會改變任何內容。

換句話說,只要文件中的數據創建的方式與您嘗試重新讀取的方式基本相同,就可以正常工作。如果它是在另一台機器上創建的,或者是使用不同的編譯器創建的(或者甚至是具有不同標志的相同編譯器)您有相當多的潛在問題 - 您可能會得到字節序,結構中的填充等等的差異。

編輯:鑒於你不知道結構是否已經以編譯器所期望的格式寫出,你不僅需要一次讀取一個結構 - 你真的需要讀取結構中的結構一個一段時間,然后將每個放入一個臨時struct ,最后將該填充struct添加到您的集合中。

幸運的是,您可以重載operator>>以自動執行大部分operator>> 它不會提高速度(例如),但它可以使您的代碼更清晰:

struct whatever { 
    int x, y, z;
    char stuff[672-3*sizeof(int)];

    friend std::istream &operator>>(std::istream &is, whatever &w) { 
       is >> w.x >> w.y >> w.z;
       return is.read(w.stuff, sizeof(w.stuff);
    } 
};

int main(int argc, char **argv) { 
    std::vector<whatever> data;

    assert(argc>1);

    std::ifstream infile(argv[1]);

    std::copy(std::istream_iterator<whatever>(infile),
              std::istream_iterator<whatever>(),
              std::back_inserter(data));  
    return 0;
}

對於您現有的文件,最好的辦法是找出其文件格式,並單獨讀取每種類型,讀入並丟棄任何對齊字節。

最好不要對結構對齊做任何假設。

要將新數據保存到文件,可以使用boost序列化等功能

在您的情況下,只要可能改變結構布局,就需要關注對齊。 有兩種方法可以使您的代碼更具可移植性。

首先,大多數編譯器都有擴展屬性或預處理程序指令,這些指令允許您將結構打包到最小的空間。 此選項可能會錯誤地對齊結構中的某些字段,這可能會降低性能,但會保證在為其構建的任何計算機上布局相同。 檢查編譯器有關#pragma pack()文檔。 在GCC中,您可以使用__attribute__((__packed__))

其次,您可以為結構添加顯式填充。 此選項允許您維護原始結構的性能屬性,但會明確說明結構的布局方式。 例如:

struct s {
    u_int8_t  field1;
    u_int8_t  pad0[3];
    u_int16_t field2;
    u_int8_t  pad1[2];
    u_int32_t field3;
};

不僅僅是對齊,你應該擔心字節序 STL保證vector中的存儲與數組相同,但結構本身中的整數字段將以x86和RISC之間的不同格式存儲。

至於對齊的東西,Google為#pragma pack(1)

如果您正在編寫需要了解類的內部工作原理的OO代碼,那么您做錯了。 你不應該對課程的內部運作有任何假設; 您應該只假設方法和屬性在任何平台/編譯器上的工作方式相同。

你可能會更好地實現一個模擬向量功能的類(可能通過子類化向量)。 可能作為“代理模式”實現,它只能加載調用者訪問過的那些結構。 這樣您就可以同時處理任何字節序問題。 這種方式應該適用於任何平台或編譯器。

暫無
暫無

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

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