2011-11-10 55 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() 

干杯。

相关问题