简体   繁体   English

从byte []到struct的类型转换

[英]Typecasting from byte[] to struct

I'm currently working on a small C++ project where I use a client-server model someone else built. 我目前正在研究一个小型C ++项目,在这里我使用别人构建的客户端-服务器模型。 Data gets sent over the network and in my opinion it's in the wrong order. 数据是通过网络发送的,我认为顺序错误。 However, that's not something I can change. 但是,这不是我可以更改的。

Example data stream (simplified): 示例数据流(简化):

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)

I can represent this specific stream as : 我可以将此特定流表示为:

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

And I can typecast it with test *t = (test*)stream; 我可以使用test *t = (test*)stream;进行类型转换test *t = (test*)stream; However, the char* has a variable length. 但是,char *具有可变长度。 It is, however, always null terminated. 但是,它始终为null终止。

I understand that there's no way of actually casting the stream to a struct, but I was wondering whether there would be a better way than struct test() { test(char* data) { ... }} (convert it via the constructor) 我了解没有办法将流实际转换为结构,但是我想知道是否有比struct test() { test(char* data) { ... }} (通过构造函数转换struct test() { test(char* data) { ... }}更好的方法)

This is called Marshalling or serialization . 这称为编组序列化

What you must do is read the stream one byte at a time (or put all in a buffer and read from that), and as soon as you have enough data for a member in the structure you fill it in. 您必须做的是一次读取一个字节流(或将其全部放入缓冲区并从中读取),并且一旦有足够的数据供结构中的成员使用,就填充它。

When it comes to the string, you simply read until you hit the terminating zero, and then allocate memory and copy the string to that buffer and assign it to a pointer in the struct. 当涉及到字符串时,您只需读取直到达到终止零,然后分配内存并将该字符串复制到该缓冲区,然后将其分配给该结构中的指针即可。

Reading strings this way is simplest and most effective if you have of the message in a buffer already, because then you don't need a temporary buffer for the string. 如果您已经将消息存储在缓冲区中,则以这种方式读取字符串是最简单且最有效的,因为这样就不需要为该字符串设置临时缓冲区。

Remember though, that with this scheme you have to manually free the memory containing the string when you are done with the structure. 但是请记住,使用此方案时,必须在完成结构后手动释放包含字符串的内存。

Just add a member function that takes in the character buffer(function input parameter char * ) and populates the test structure by parsing it. 只需添加一个成员函数,该成员函数接受字符缓冲区(函数输入参数char * )并通过对其进行分析来填充test结构。
This makes it more clear and readable as well. 这也使它更清晰易读。

If you provide a implicit conversion constructor then you create a menace which will do the conversion when you least expect it. 如果提供隐式转换构造函数,则会创建一个威胁,它将在您最不期望的时候进行转换。

When reading variable length data from a sequence of bytes, you shouldn't fit everything into a single structure or variable. 从字节序列读取可变长度数据时,不应将所有内容都放入单个结构或变量中。 Pointers are also used to store this variable length. 指针还用于存储此可变长度。

The following suggestion, is not tested: 以下建议未经测试:

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

Cheers. 干杯。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM