2009-11-09 36 views
9

我想通過網絡傳輸數據,但我不想使用任何外部庫(標準C/C++是好的)。序列化字符串,整數和浮點數字網絡無庫

例如:

unsigned int x = 123; 
char y[3] = {'h', 'i', '\0'}; 
float z = 1.23f; 

我想這在

char xyz[11]; 

陣列。我需要無符號int(htonl函數)的網絡字節順序,然後我需要以某種方式將浮點數序列化爲IEEE 754格式(因特網上的許多函數),然後,我知道它。

我該如何將它們放入xyz-Array,很好地排隊,所以我可以使用它作爲我的socket + send()函數的緩衝區?很顯然,我有反向功能(再用ntohl和反向IEEE 754),讓他們出來,但我需要的技術有太多,最好是相同的......

這將是這樣的:

 
xyz in binary: 
00000000 0000000 00000000 01111011 | 01101000 | 01101001 | 00000000 | 00111111 10011101 01110000 10100100 
- big endian repr. of u. int 123 - | - 'h' - | - 'i' - | - '\0' - | - IEEE 754 repr of float 1.23 - 

我如何在沒有外部庫的情況下完成此任務並最小化標準庫函數的使用?這不是我的課程,而是我學習的課程。

+0

首先,你並沒有在任何地方實際聲明y變量。它是一個字符數組嗎?你知道這些陣列有多大,還是它們是動態的? – 2009-11-09 19:56:36

+0

對不起,我顯然無法用雙引號中的字符串字面值初始化y,我解決了這個問題。它的大小是3個字節。 – wsd 2009-11-09 19:58:33

回答

16

啊,你要序列原始數據類型!原則上,有兩種方法:第一種方法是,您只需獲取要序列化的數據的內部二進制表示形式,將其重新解釋爲字符,然後將其用作字符表示即可:

所以如果你有:

double d;

你拿的這個地址

,重新解釋該指針指向字符,然後使用這些字符:

double *pd=&d; 
char *pc = reinterpret_cast<char*>(pd); 
for(size_t i=0; i<sizeof(double); i++) 
{ 
    char ch = *pc; 
    DoSomethingWith(ch); 
    pc++; 
} 

這適用於所有的基本數據類型。這裏的主要問題是,Binray表示是實現相關的(主要取決於CPU)。 (當你嘗試用IEEE NANs做這件事時,你會遇到微妙的錯誤...)。

總而言之,這種方法根本不可移植,因爲您無法控制數據的表示形式。

第二種方法是,使用更高級別的表示法,您自己可以控制。如果性能不是問題,則可以使用std :: strstream和>>和運算符將原始C類型變量編譯爲std :: strings。這很慢,但易於閱讀和調試,並且非常便於使用。

+0

+1用於突出顯示問題,並添加未定義的填充。而且我會咬牙切齒:)在這種情況下,IEEE NaN有哪些微妙的缺陷?謝謝.. – 2009-11-09 20:41:15

+1

有信令NaNs和非信號NaNs。當您將這些表示形式用作字符數組時,您可以輕鬆地讀取和寫入它們。但是當你將它們作爲浮點數訪問時,只要讀取它們就可以使CPU發出信號。所以如果你不小心的話,你可以用一個沒有問題的反序列化程序來結束,但是一旦你碰到浮子,你就會陷入困境。由於這個主題是關於學習的,我想我可能會指出這個領域。 – 2009-11-09 20:48:24

+0

+ 1,我沒有看到它在這裏提到的這個上下文..雖然供應商傾向於避免編組,以及序列化任何形式的浮動,最後:) – 2009-11-09 21:25:17

0

你的目標是什麼?你願意使用什麼手段?

如果你只是想在一臺特定的計算機上用一個特定的編譯器完成工作,那麼最快,最簡單但最骯髒的解決方案就是使用聯合。您可以定義一個將項目作爲成員的結構,並將其與字符數組合並。您需要告訴編譯器緊緊包裝成員,這與#pragma pack(1)一致,並且解決了您的問題。您只需將這三個值存儲在成員中,然後將其視爲字符數組。

如果機器是小端,並且需要大端英寸/浮點數,則只需交換相關字符。

但是如果你有其他的目標,比如可移植性,非標準字節順序,sizeof(int)!= 4,float不是以IEEE格式在內部存儲等,至少還有另外的解決方案。

+0

我想學習在C/C++中序列化原始C/C++數據類型(以便我可以在後面添加序列化結構的知識)。手段是GCC接受的任何C/C++函數和標準C/C++庫函數。謝謝,我會研究工會。 – wsd 2009-11-09 20:12:16

8

類似下面的代碼會做到這一點。注意sizeof(unsigned int)在不同系統上不同的問題,這些問題會爲你帶來幫助。對於這樣的事情,最好使用具有定義好的大小的類型,比如int32_t。無論如何...

unsigned int x = 123; 
char y[3] = {'h', 'i', '\0'}; 
float z = 1.23f; 

// The buffer we will be writing bytes into 
unsigned char outBuf[sizeof(x)+sizeof(y)+sizeof(z)]; 

// A pointer we will advance whenever we write data 
unsigned char * p = outBuf; 

// Serialize "x" into outBuf 
unsigned int32_t neX = htonl(x); 
memcpy(p, &neX, sizeof(neX)); 
p += sizeof(neX); 

// Serialize "y" into outBuf 
memcpy(p, y, sizeof(y)); 
p += sizeof(y); 

// Serialize "z" into outBuf 
int32_t neZ = htonl(*(reinterpret_cast<int32_t *>(&z))); 
memcpy(p, &neZ, sizeof(neZ)); 
p += sizeof(neZ); 

int resultCode = send(mySocket, outBuf, p-outBuf, 0); 
[...] 

...當然,接收代碼會做類似的事情,除了相反。

1

discussion似乎有關你的問題,但它使用升壓序列化API

+0

我認爲Boost會教你很多(你可以查看實現)。並且還會爲您提供一個您無法想象的衆多問題的現成解決方案。 – 2009-11-09 20:19:17

+0

我正在瀏覽Boost Serialization API,因爲我編寫了這個(在另一個Tab xD中),但它看起來像我想要做的那樣是Overkill。試圖以編程方式提取它... – wsd 2009-11-09 20:27:39