[英]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;
}
這就是我理解(或不理解)的方式。
反序列化幾乎相同,但順序相反,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.