1

バイナリリクエストを作成して記述しようとしていますが、「これは可能ですか」というタイプの質問があります。リクエストの受信者は、以下に含めたデータ構造を認識していないことに言及することが重要かもしれません。これは、バイトのシーケンスを想定しているだけですが、構造体を使用すると、リクエストの一部を準備するための便利な方法のように見えました。その後、それらを簡単に記述します。

ヘッダーとフッターは固定サイズなので書き込みは問題ありませんが、ベクトルが原因で構造体「詳細」で問題が発生しています。今のところ、リクエストを確認できるようにファイルに書き込んでいるのは仕様ですが、最終的にはブーストasioシリアルポートを使用してPLCに書き込むことを目的としています。

このような構文を使用して構造体を記述できますが、ベクトルに到達すると、値ではなくポインターアドレスが書き込まれます。

myFile.write((char*) &myDataRequest, drSize);

この構文を使用してベクトルを単独で書き込むことはできますが、値を書き込むには0にインデクサーを含める必要があります

myFile.write((char*) &myVector[0], vectorSize);

ベクトル(または他の適切なコレクション)を含む構造体を一度にバイナリ書き込みするエレガントな方法はありますか?たとえば、ベクトルを別の方法で宣言した場合や、構造体内のコンテンツに対して複数の書き込みを行うことを辞任した場合などです。ベクトルを配列に置き換えると、構造体を一度に送信できますが(インデクサーを含める必要はありません)、実行時まで必要なサイズがわからないため、適切ではないと思います。

私の構造

    struct Header
    {   ...     };

    struct Details
    {
           std::vector<DataRequest> DRList;
    };

    struct DataRequest
    {
           short numAddresses;          // Number of operands to be read   Bytes 0-1
           unsigned char operandType;   //                                  Byte 2
           unsigned char Reserved1;     //Should be 0xFF                    Byte 3
           std::vector<short> addressList;  // either, starting address (for sequence), or a list of addresses (for non-sequential) 
    };

    struct Footer
    {   ...     };
4

3 に答える 3

2

std::vectorオブジェクトには実際には配列が含まれておらず、メモリのブロックへのポインターが含まれているため、これは不可能です。ただし、そのような生の構造体を記述できることは望ましくないと主張したくなります。

  1. 構造体をメモリのブロックとして扱うと、最終的にパディング バイトが送信される可能性があると思いますが、これは望ましくないと思います。

  2. 書き込む内容によっては、書き込みがとにかくバッファリングされることがわかる場合があるため、複数の書き込み呼び出しは実際には効率が低下しません。

  3. 送信されるフィールドで何かをしたい場合があります。特に、送信する数値を使用します。これには、伝送の両側が同意するバイト順序を適用する必要があります。移植可能にするためには、バイト順を明示的に変換して、ソフトウェアが移植可能であることを確認する必要があります (必要な場合)。

長い話を簡単に言うと、各フィールドを 1 つずつ書き出すことは、効率が悪いわけではなく、より正確でもあると思います。

于 2012-09-25T12:42:41.313 に答える
1

これは、実際には良い戦略ではありません。これができたとしても、メモリの内容をファイルに直接コピーしていることになるからです。アーキテクチャ/プロセッサを変更すると、クライアントは異なるデータを取得します。構造体とファイル名を使用して構造体の値を個別に書き込み、その内容を書き出すベクトルを反復処理するメソッドを作成すると、クライアントが期待するバイナリ形式を完全に制御でき、コンパイラの現在のメモリに依存しなくなります。表現。

マーシャリング/アンマーシャリングの利便性が必要な場合は、boost::serializationライブラリを参照してください。彼らは (テキストと xml に加えて) バイナリ アーカイブを提供しますが、独自の形式 (たとえば、データのダンプに使用されたシリアライゼーション ライブラリのバージョン番号がある) を持っているため、クライアントが望んでいるものではない可能性があります。

于 2012-09-25T12:42:12.157 に答える
1

What exactly is the format expected at the other end? You have to write that, period. You can't just write any random bytes. The probability that just writing an std::vector like you're doing will work is about as close to 0 as you can get. But the probability that writing a struct with only int will work is still less than 50%. If the other side is expecting a specific sequence of bytes, then you have to write that sequence, byte by byte. To write an int, for example, you must still write four (or whatever the protocol requires) bytes, something like:

byte[0] = (value >> 24) & 0xFF;
byte[1] = (value >> 16) & 0xFF;
byte[2] = (value >>  8) & 0xFF;
byte[3] = (value      ) & 0xFF;

(Even here, I'm supposing that your internal representation of negative numbers corresponds to that of the protocol. Usually the case, but not always.)

Typically, of course, you build your buffer in a std::vector<char>, and then write &buffer[0], buffer.size(). (The fact that you need a reinterpret_cast for the buffer pointer should signal that your approach is wrong.)

于 2012-09-25T12:51:43.320 に答える