2011-11-10 10 views
1

私は現在、他の誰かが構築したクライアント/サーバーモデルを使用する小さなC++プロジェクトに取り組んでいます。データはネットワークを介して送信され、私の意見では間違った順序です。しかし、それは私が変えることのできるものではありません。byte []からstructに型キャストする

例データストリーム(簡体字):

0x20 0x00 (C++: short with value 32) 
0x10 0x35 (C++: short with value 13584) 
0x61 0x62 0x63 0x00 (char*: abc) 
0x01 (bool: true) 
0x00 (bool: false) 

私は、この特定のストリームを表すことができる:

struct test { 
    short sh1; 
    short sh2; 
    char abc[4]; 
    bool bool1; 
    bool bool2; 
} 

そして、私はしかし、チャー*は可変長を有するtest *t = (test*)stream;でそれを型キャストすることができます。ただし、常にnullで終了します。

は、私が実際に構造体へのストリームをキャストする方法はありませんことを理解し、私はstruct test() { test(char* data) { ... }}(コンストラクタを介してそれを変換)よりも良い方法があるだろうかどうか迷った

+2

Yuk、バイナリシリアル化。エンディアンを補う。 –

+1

'char *'は決して可変長ではありません。それは常に 'char * 'のサイズです。 –

+0

@Tom van der Woerdt "abc"で参照されるデータが "Nullで終わる文字列"であり、サイズが変わる可能性があります。愚かな質問のように聞こえるが、明確にするのが良い;-) – umlcat

答えて

2

だけ取るメンバ関数を追加文字バッファ(関数入力パラメータchar *)に格納し、それを構文解析してtest構造体に移入します。
このようにすると、より明確で読みやすくなります。

暗黙的コンバージョンコンストラクタを指定すると、予想以上にコンバージョンを行う脅威が作成されます。

+3

明示的な変換コンストラクタは、初期化されていないオブジェクトを作成するよりも優れています。 –

+2

'explicit'キーワードがあり、それは価値があります。 –

+0

合意。「明示的」は、厄介な暗黙の変換から保護しますが、読みにくく、目的を明確に示すため、意味のある名前の関数がここにあります。 –

3

Marshallingまたはserializationと呼ばれています。

一度に1バイトずつストリームを読み込む(またはバッファにすべてを入れて読み込みます)、構造内のメンバーに十分なデータがあるとすぐに入力してください。

文字列の場合は、終端のゼロに達するまで読み込み、メモリを割り当ててその文字列をそのバッファにコピーし、構造体のポインタに代入します。

この方法で文字列を読み込むのは、バッファにメッセージがある場合は最も簡単で効果的です。文字列の一時バッファは不要なためです。

このスキームでは、構造体の処理が完了したら、文字列を含むメモリを手動で解放する必要があります。

+2

または彼がC++を使っているので、彼は単純に 'std :: string'を使うことができます –

0

バイトシーケンスから可変長データを読み取るときは、 をすべて単一の構造体または変数に収めるべきではありません。 ポインタもこの可変長を格納するために使用されます。

以下の提案は、テストされていません。

// data is stored in memory, 
// in a different way, 
// NOT as sequence of bytes, 
// as provided 
struct data { 
    short sh1; 
    short sh2; 
    int abclength; 
    // a pointer, maybe variable in memory !!! 
    char* abc; 
    bool bool1; 
    bool bool2; 
}; 

// reads a single byte 
bool readByte(byte* MyByteBuffer) 
{ 
    // your reading code goes here, 
    // character by character, from stream, 
    // file, pipe, whatever. 
    // The result should be true if not error, 
    // false if cannot rea anymore 
} 

// used for reading several variables, 
// with different sizes in bytes 
int readBuffer(byte* Buffer, int BufferSize) 
{ 
    int RealCount = 0; 

    byte* p = Buffer; 

    while (readByte(p) && RealCount <= BufferSize) 
    { 
     RealCount++ 
     p++; 
    } 

    return RealCount; 
} 

void read() 
{ 
    // real data here: 
    data Mydata; 

    byte MyByte = 0; 

    // long enough, used to read temporally, the variable string 
    char temp[64000]; 
    // fill buffer for string with null values 
    memset(temp, '\0', 64000); 

    int RealCount = 0; 

    // try read "sh1" field 
    RealCount = (readBuffer(&(MyData.sh1), sizeof(short))); 
    if (RealCount == sizeof(short)) 
    { 
     // try read "sh2" field 
     RealCount = readBuffer(&(MyData.sh2), sizeof(short));  
     if (RealCount == sizeof(short)) 
     { 
      RealCount = readBuffer(temp, 64000); 
      if (RealCount > 0) 
      { 
       // store real bytes count 
       MyData.abclength = RealCount; 
       // allocate dynamic memory block for variable length data 
       MyData.abc = malloc(RealCount); 
       // copy data from temporal buffer into data structure plus pointer 
       // arrays in "plain c" or "c++" doesn't require the "&" operator for address: 
       memcpy(MyData.abc, temp, RealCount); 

       // comented should be read as: 
       //memcpy(&MyData.abc, &temp, RealCount); 

       // continue with rest of data 
       RealCount = readBuffer(&(MyData.bool1), sizeof(bool)); 
       if (RealCount > 0) 
       { 
        // continue with rest of data 
        RealCount = readBuffer(&(MyData.bool2), sizeof(bool)); 
       } 
      } 
     } 
    } 
} // void read() 

乾杯を。

関連する問題