2011-11-10 98 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」引用的數據是一個「空終止的字符串」,可能會改變它的大小。聽起來像一個愚蠢的問題,但是,它更好清楚;-) – umlcat

回答

2

只需添加一個成員函數,它在字符緩衝區中(函數輸入參數char *),並通過解析它來填充test結構。
這使得它更清晰可讀。

如果您提供了一個隱式轉換構造函數,那麼您創建了一個威脅,當您最不期待它時會進行轉換。

+3

儘管'explicit'轉換構造函數可能會比允許您創建未初始化的對象更好。 –

+2

有'explicit'關鍵字,它是值得的。 –

+0

同意.'explicit'可以避免尷尬的隱式轉換,但它的可讀性還不夠好,具有有意義名稱的函數在這裏很適合,因爲它清楚地表明瞭目的。 –

3

這叫做Marshallingserialization

那你必須做的是閱讀在時間的流裏一個字節(或把所有的緩衝區,並從該讀取),以及只要你有足夠的數據以供您填寫到結構的成員。

當涉及到字符串時,您只需閱讀,直到找到終止零,然後分配內存並將該字符串複製到該緩衝區,並將其分配給結構中的指針。

以這種方式讀取字符串是最簡單和最有效的,如果您已經在緩衝區中存在消息,因爲那樣您不需要字符串的臨時緩衝區。

請記住,使用此方案時,必須在完成結構時手動釋放包含字符串的內存。

+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() 

乾杯。

相關問題