簡體   English   中英

使用指向結構的指針序列化結構

[英]Serialize struct with a pointer to a struc

我正在嘗試關注https://accu.org/index.php/journals/2317上寫的一篇文章,我發現這很有趣,因為我正在嘗試深入了解一些管理工具的序列化/文件保存/加載我正在嘗試。 我將它標記為 c++,因為在我讓它工作后,我會將它包裝在 class 上(希望在你的幫助下)。

現在,這是出於學習目的,因為我目前不打算使用 boost 或任何其他序列化庫。 我想知道或嘗試找出這些東西是否有效。

目前,我必須做一些細微的修改才能工作,因為斷言總是錯誤的並且在嘗試使用 memcpy 分配 memory 外部寫入時遇到問題。

現在,它可以編譯,但是當我對結構進行序列化和反序列化時,數據是不一樣的。

請查看並幫助我,或指出我正確的方向。 在代碼之后,我將嘗試解釋我是如何理解它的。

#include <iostream>
#include <cassert>

struct Y
{
    int yy;
};

struct X
{
    int xx;
    struct Y* y = nullptr;
    int z;
};

// Changed OutMemStram and InMemStream for IOMemStream, same data
struct IOMemStream
{
    // changed from uint8_t* to char*
    char* pp;
    char* ppEnd;
};

// Output
inline void WriteToStream( IOMemStream* dst, void* p, size_t sz )
{
    dst->pp = (char*)p; // original code doesn't contain this line
    dst->ppEnd = (char*)p + sz; // original code doesn't contain this line

    assert( (dst->pp + sz) <= dst->ppEnd );
    memcpy( dst->pp, p, sz );
    dst->pp += sz;
}

void SerializeX( IOMemStream* dst, X* x )
{
    WriteToStream( dst, x, sizeof( X ) );
    WriteToStream( dst, x->y, sizeof( Y ) );
}

// Input
inline void ReadFromStream( IOMemStream* src, void* p, size_t sz ) 
{
    //assert( (src->pp + sz) <= src->ppEnd );

    memcpy( p, src->pp, sz );
    src->pp += sz;
}

void DeserializeX( IOMemStream* src, X* x ) 
{
    ReadFromStream( src, x, sizeof( X ) );
    // x->y contains garbage at this point(!)
    // ok, not exactly garbage - but a pointer
     // which is utterly invalid in our current space
    x->y = new Y;
    assert( x->y );
    ReadFromStream( src, x->y, sizeof( Y ) );
}


// Usage sample
int main()
{
    // Assume struct x was previously filled by other function
    X x;
    x.xx = 1000;
    x.z = 2000;
    x.y = new Y;
    x.y->yy = 3000;

    // IO buffer
    IOMemStream ioms;

    // Test for output
    SerializeX( &ioms, &x );

    // Test for input
    X x1;
    DeserializeX( &ioms, &x1 );

    // x1.xx should be 1000 and x1.< should be 2000
    std::cout << x1.xx << ", " << x1.z << std::endl;

    delete x.y;
    delete x1.y;
    //delete ioms.pp; // gets exception

    std::cin.get();
    return 0;
}

這就是我理解(或不理解)的方式。

  1. 結構 X,包含 2 個整數和 1 個指向 Y 結構的結構指針,假設 int size = 4,那么 X 的大小將為 12 個字節。 Y 它是 4 個字節。
  2. IOMemStream 包含 struct X 和 struct Y 的指針。
  3. IOMemStream->pp 和 IOMemStream->ppEnd 應該有 12 個字節和來自 struct X 和 X->Y 的 4 個字節。
  4. Function WriteToStream 將結構中的字節打包到 pp 和 ppEnd 指針,在分配 X 后,指針增加大小以准備 Y 結構。 (在原始文章中,斷言是在沒有分配變量 pp 和 ppEnd 的情況下進行的
  5. IOMemStream) Function SerializeX 對 X 和 Y 結構都使用 WriteToStrea。

反序列化幾乎相同,但順序相反,ReadFromStream 將為結構 Y 分配 memory。

我從這里迷路了,因為序列化和反序列化的值不一樣。 另外,我希望我理解正確:D

先感謝您!

免責聲明:這只是一堆太長的評論,不能寫成評論,而不是正確的答案。


事情不是那么簡單,你有一些錯誤的假設。 特別是,即使一個int占用 4 個字節而一個指針占用 8 個字節,由於填充,您的X結構可以有超過 16 個字節。

嘗試將下面的代碼添加到您的 main 中,看看您會得到什么

    X x;
    std::cout << sizeof(x.xx) << std::endl;
    std::cout << sizeof(x.y) << std::endl;
    std::cout << sizeof(x.z) << std::endl;
    std::cout << sizeof(x) << std::endl;

在我的系統中,每個 integer 得到 4 個字節,指針得到 8 個字節,但對於結構,我得到 24 個字節。 原因是由於填充( 有關更多信息,請參閱此問題)。 請注意,您聲明結構成員的順序對填充有影響。 相反,如果您聲明

struct X {
    struct Y* y = nullptr;
    int xx;
    int z;
};

or

```c++
struct X {
    int xx;
    int z;
    struct Y* y = nullptr;
};

那么該結構將只需要 16 個字節(至少在我的系統中)。


另一個問題是序列化指針。 顯然,存儲指針值用處不大。 您將需要考慮如何處理 struct Y 您必須在反序列化過程中創建一個Y類型的 object,然后將其地址放入反序列化的結構X中,但細節可能會根據程序的 rest 而改變,這里我們只有示例代碼。


最后,小心memcpy ,因為它只會保存字節(可能包括填充)並且它不關心字節順序。

我多讀了這篇文章,似乎他們在 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ object 中收到的數據來自機器,這就是為什么 pp 和 ppend,可能有“之前和之后”保存的 Z9ED39E2EA931586B6EZEF5。 另外,這些功能似乎只是為了這個目的。

太糟糕了,因為我認為這是一種可以學習的好代碼,可能我對它感到沮喪並且錯過了理解這個概念。

抱歉浪費你們的時間,伙計們:但我不會放棄:)

有任何書籍或網站可以了解更多關於序列化的信息嗎? 目前我不想使用任何外部庫,因為我想了解更多並練習使用自己的工具。 出於某種原因,使用外部庫對我來說就像在作弊,讓我覺得我沒有走正確的道路。

謝謝,問候!

暫無
暫無

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

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