2010-07-19 14 views
2

我有一個「消息」的二進制文件,我試圖使用結構適合正確的變量內的字節。在我的例子中,我使用了兩種類型的消息:Tmessage和Amessage。如何擺脫結構的數據成員之間的填充字節

#include <iostream> 
#include <fstream> 
#include <stdlib.h> 
#include <string> 
#include <iomanip> 

using namespace std; 

struct Tmessage 
{ 
    unsigned short int Length; 
    char MessageType; 
    unsigned int Second; 
}; 

struct Amessage 
{ 
    unsigned short int Length; 
    char MessageType; 
    unsigned int Timestamp; 
    unsigned long long int OrderReferenceNumber; 
    char BuySellIndicator; 
    unsigned int Shares; 
    char Stock[6]; 
    unsigned int Price; 
}; 

int main(int argc, char* argv[]) 
{ 
    const char* filename = argv[1]; 
    fstream file(filename, ios::in | ios::binary); 
    unsigned long long int pi = 0; 

    if(file.is_open()){ cout << filename << " OPENED" << endl; } 
    else { cout << "FILE NOT OPENED" << endl; } 

    unsigned char* memblock; 
    memblock = new unsigned char[128]; 
    file.read((char *)memblock, 128); 

    cout << "BINARY DATA" << endl; 
    while (pi < 128) 
    { 
     cout << setw(2) << hex << static_cast<unsigned int>(memblock[pi]) << " "; 
     pi++; 
     if((pi%16)==0) cout << endl; 
    } 

    unsigned int poi = 0; 

    Tmessage *Trecord; 
    Trecord = (Tmessage *)memblock; 
    cout << "Length: " << hex << (*Trecord).Length << endl; 
    cout << "Message type: " << hex << (*Trecord).MessageType << endl; 
    cout << "Second: " << hex << (*Trecord).Second << endl; 

    poi = poi + 7; cout << endl; 

    Amessage *Arecord; 
    Arecord = (Amessage *)(memblock+poi); 
    cout << "Length: " << hex << (*Arecord).Length << endl; 
    cout << "Message type: " << hex << (*Arecord).MessageType << endl; 
    cout << "Timestamp: " << hex << (*Arecord).Timestamp << endl; 
    cout << "OrderReferenceNumber: " << hex << (*Arecord).OrderReferenceNumber << endl; 
    cout << "BuySellIndicator: " << hex << (*Arecord).BuySellIndicator << endl; 
    cout << "Shares: " << hex << (*Arecord).Shares << endl; 
    cout << "Stock: " << hex << (*Arecord).Stock << endl; 
    cout << "Price: " << hex << (*Arecord).Price << endl; 

    delete memblock; 
    file.close(); 
    cout << endl << "THE END" << endl; 
    return 0; 
} 

當我運行該程序的輸出:

stream OPENED 
BINARY DATA 
0 5 54 0 0 62 72 0 1c 41 0 f 42 40 0 0 
0 0 0 4 2f 76 53 0 0 3 e8 53 50 59 20 20 
20 0 11 5 d0 0 1c 41 0 f 42 40 0 0 0 0 
0 4 2f 78 42 0 0 3 e8 53 50 59 20 20 20 0 
10 f7 5c 0 1c 41 0 f 42 40 0 0 0 0 0 4 
2f 90 53 0 0 1 2c 53 50 59 20 20 20 0 11 2 
b0 0 5 54 0 0 62 76 0 d 44 14 25 78 80 0 
0 0 0 0 4 2f 90 0 d 44 14 25 78 80 0 0 
Length: 500 
Message type: T 
Second: 726200 

Length: 1c00 
Message type: A 
Timestamp: 40420f 
OrderReferenceNumber: 53762f0400000000 
BuySellIndicator: 
Shares: 20595053 
Stock: 
Price: 420f0041 

THE END 

的程序放置字節Tmessage內部結構正常。 (0 5 54 0 0 62 72)
但是,解析Amessage時發生了某些情況。
(0 1C 41 0,F 42 40 0 0 0 0 0 4 2F 76 53 0 0 3 E8 53 50 59 20 20 20 0 11 5 D0)

的Lenght,消息類型和時間戳是正確的,但OrderReferenceNumber包含「53」字節屬於BuySellIndicator,然後另一個變量是不正確的。

正確的消息輸出應該是:
長度:1C 0
消息類型:41
時間戳:40 42 f 0的
OrderReferenceNumber:76 2F 4 0 0 0 0 0
BuySellIndicator:53
股數:E8 3 0 0
庫存:53 50 59 20 20 20
價格:D0 5 11 0

的2個問題: a)爲什麼OrderReferenceNumber包含「53」字節? b)我認爲「char stock [6]」不起作用,因爲在Share的字節和Price的字節之間有超過6個字節。我如何將6個字節放入char向量或字符串?

注意:我知道我必須交換字節,因爲二進制數據以big-endian結尾。這就是爲什麼「股票」不應該交換。 非常感謝您的幫助!親切的問候,

回答

2

編譯器可能在您的結構的成員之間插入填充字節。解決這個問題的一種方法是使用編譯指示包。請注意,這是非標準的,但它適用於g ++和visual C++。

#pragma pack (push, 1) 
struct Amessage 
{ 
    unsigned short int Length; 
    char MessageType; 
    unsigned int Timestamp; 
    unsigned long long int OrderReferenceNumber; 
    char BuySellIndicator; 
    unsigned int Shares; 
    char Stock[6]; 
    unsigned int Price; 
}; 
#pragma pack (pop) 

什麼上面要在代碼是:編譯包告訴你不希望它插入填充以讓這個它會進行對齊訪問結構成員的編譯器。 push/pop的東西是這樣的,你可以嵌套#pragma包(例如,當包含頭文件時)並且有辦法返回到先前設置的包選項。

有關可能比我可以提供的解釋更好的解釋,請參閱MSDN。 http://msdn.microsoft.com/en-us/library/2e70t5y1%28VS.80%29.aspx

4

在結構的數據成員之間可能有未命名的填充字節。

爲了以便攜方式從文件中讀取二進制數據,您應該逐個讀取結構中的每個成員。

你也應該使用<cstdint>指定的確切寬度類型(升壓有這個頭的實現,如果你的標準庫沒有它尚未);這將允許您確保數據成員的大小與郵件中字段的大小相匹配。

+0

編譯器(對齊/不對齊)指令也可能影響結構和對象的填充,因此即使對於不可移植的程序也是如此,否則它可能會因不明顯的原因而表現不同。 – 2010-07-19 01:24:35