1

私が所有していないクラスがあるとしましょう: DataBuffer. さまざまな get メンバー関数を提供します。

get(uint8_t *value);
get(uint16_t *value); 
...

このバッファーに含まれる構造体から読み取る場合、フィールドの順序とサイズがわかっているので、将来のコード変更でエラーが発生する可能性を減らしたいと考えています。

struct Record 
{
    uint16_t Header;
    uint16_t Content;
}

void ReadIntoRecord(Record* r)
{
    DataBuffer buf( initialized from the network with bytes )
    buf.get(&r->Header); // Good!
    buf.get(&r->Content);
}

次に、誰かが変更をチェックインして、ヘッダーを書き込む前に何かを行います。

    uint8_t customHeader;
    buf.get(&customHeader);  // Wrong, stopped reading after only 1 byte
    r->Header = customHeader + 1;
    buf.get(&r->Content);  // now we're reading from the wrong part of the buffer.

以下は、変更に対してコードを強化するための受け入れ可能な方法ですか? 関数名を getByte や getUShort などに変更することはできません。DataBuffer から継承することもできますが、それはやり過ぎのように思えます。

    buf.get(static_cast<uint16_t*>(&r->Header));  // compiler will catch incorrect variable type
    buf.get(static_cast<uint16_t*>(&r->Content))

目に安全ではないレガシーコードの例で更新されました:

       float dummy_float;
        uint32_t dummy32;
        uint16_t dummy16;
        uint8_t dummy8;

        uint16_t headTypeTemp;
        buf.get(static_cast<uint16_t*>(&headTypeTemp));
        m_headType = HeadType(headTypeTemp);
        buf.get(static_cast<uint8_t*>(&hid));
        buf.get(m_Name);
        buf.get(m_SerialNumber);


        float start;
        buf.get(static_cast<float*>(&start));
        float stop;
        buf.get(static_cast<float*>(&stop));


        buf.get(static_cast<float*>(&dummy_float));
        setStuffA(dummy_float);

        buf.get(static_cast<uint16_t*>(&dummy16));
        setStuffB(float(dummy16)/1000);

        buf.get(static_cast<uint8_t*>(&dummy8));    //reserved





        buf.get(static_cast<uint32_t*>(&dummy32));
        Entries().setStart( dummy32 );
        buf.get(static_cast<uint32_t*>(&dummy32));
        Entries().setStop( dummy32 );
        buf.get(static_cast<float*>(&dummy_float));
        Entries().setMoreStuff( dummy_float );

        uint32_t datalength;
        buf.get(static_cast<uint32_t*>(&datalength));

        Entries().data().setLength(datalength);

        RetVal ret = ReturnCode::SUCCESS;
        Entry* data_ptr = Entries().data().data();
        for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
        {
            ret = buf.get(static_cast<float*>(&dummy_float));
            data_ptr[i].FieldA = dummy_float;
        }

        for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
        {
            ret = buf.get(static_cast<float*>(&dummy_float));
            data_ptr[i].FieldB = dummy_float;
        }

        // Read in the normalization vector
        Util::SimpleVector<float> norm;
        buf.get(static_cast<uint32_t*>(&datalength));
        norm.setLength(datalength);
        for (unsigned int i=0; i<datalength; i++)
        {
            norm[i] = buf.getFloat();
        }

        setNormalization(norm);

        return ReturnCode::SUCCESS;
}
4

3 に答える 3

1

オーバーロードは使用しないでください。get_word持ってget_dword電話してみませんか?インターフェースは醜いものにはなりませんが、少なくとも間違いを犯すのははるかに困難です。

于 2011-08-31T22:50:43.047 に答える
1

ネットワークから構造体全体を読み取るほうがよいのではないでしょうか? ユーザーにすべてのソケット操作を実行させることは、私には悪い考えのように思えます (カプセル化されていません)。ユーザーが生のバッファデータをファイル記述子に配置できるようにする代わりに、ファイル記述子を操作するためにネットワーク上で送信したいものをカプセル化します。

みたいなのが想像できる

void readHeader(int filedes, struct Record * Header);

だからあなたはこのようなことをすることができます

struct Record 
{
  uint16_t Header;
  uint16_t Content;
  uint16_t getHeader() const { return Header; }
  uint16_t getContent() const  { return Content; }  
};

/* socket stuff to get filedes */
struct Record x;
readHeader(fd, &x);
x.getContent();
于 2011-09-01T08:26:26.877 に答える
-1

バッファーにコンテンツに関する情報が含まれていない限り、タイプ セーフでバッファーから読み取ることはできません。簡単な方法の 1 つは、各構造体に長さを追加し、少なくとも読み取られるデータがまだ適切な長さであることを確認することです。XML や ASN.1 など、型情報が提供される同様のものを使用することもできます。もちろん、あなたもそのバッファに書き込むと仮定しています。

于 2011-08-31T22:55:25.960 に答える