2

「メッセージ」を含むバイナリファイルがあり、構造体を使用して正しい変数内にバイトを収めようとしています。この例では、Tmessage と Amessage の 2 種類のメッセージを使用しました。

#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 4 2f 76 53 0 0 3 e8 53 50 59 20 20 20 0 11 5 d0)

長さ、メッセージ タイプ、およびタイムスタンプは正しいが、OrderReferenceNumber には BuySellIndicator に属する「53」バイトが含まれており、他の変数が正しくありません。

正しい A メッセージ出力は次のようになります:
長さ: 1c 0
メッセージ タイプ: 41
タイムスタンプ: 40 42 f 0
注文参照番号: 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) Share のバイトと Price のバイトの間に 6 バイト以上あるため、「char Stock[6]」は機能しないと思います。6 バイトを char ベクトルまたは文字列に収めるにはどうすればよいですか?

注: バイナリ データはビッグ エンディアンであるため、バイトを交換する必要があることは承知しています。そのため、「Stock」はスワップされるべきではありません。ご助力ありがとうございます!敬具、

4

2 に答える 2

4

構造体のデータ メンバー間に名前のないパディング バイトが存在する場合があります。

移植可能な方法でファイルからバイナリ データを読み取るには、構造体の各メンバーを個別に読み取る必要があります。

で指定されている正確な幅タイプも使用する必要があります<cstdint>(標準ライブラリにまだない場合、Boost にはこのヘッダーの実装があります)。これにより、データ メンバーのサイズがメッセージ内のフィールドのサイズと確実に一致するようになります。

于 2010-07-19T00:51:03.790 に答える
3

コンパイラは、構造体のメンバー間にパッド バイトを挿入している可能性があります。これを回避する 1 つの方法は、pragma pack を使用することです。これは非標準ですが、g++ およびビジュアル 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)

上記のコードで何が起こっているか: プラグマ pack は、構造体のメンバーへの整列アクセスを実行するように、パディングを挿入しないようにコンパイラーに指示します。プッシュ/ポップの目的は、ネストされた #pragma パック (ヘッダー ファイルを含める場合など) を保持し、以前に設定されたパック オプションに戻る方法を提供することです。

おそらく私が提供できる説明よりも優れた説明については、MSDN を参照してください。 http://msdn.microsoft.com/en-us/library/2e70t5y1%28VS.80%29.aspx

于 2010-07-19T01:28:51.390 に答える