Типирование от байта [] до структуры - PullRequest
1 голос
/ 10 ноября 2011

В настоящее время я работаю над небольшим проектом C ++, в котором я использую модель клиент-сервер, созданную кем-то другим.Данные передаются по сети, и, по моему мнению, они находятся в неправильном порядке.Однако это не то, что я могу изменить.

Пример потока данных (упрощенно):

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; Однако, char * имеет переменную длину.Однако он всегда завершается нулем.

Я понимаю, что на самом деле нет способа привести поток к структуре, но мне было интересно, будет ли лучший способ, чем struct test() { test(char* data) { ... }} (преобразовать его черезконструктор)

Ответы [ 3 ]

3 голосов
/ 10 ноября 2011

Это называется Marshalling или сериализация .

Что вы должны сделать, это прочитать поток по одному байту за раз (или поместить все в буфер и прочитать из него), и как только у вас будет достаточно данных для члена в структуре, вы заполняете его.

Когда дело доходит до строки, вы просто читаете, пока не достигнете завершающего нуля, а затем выделяете память и копируете строку в этот буфер и назначаете ее указателю в структуре.

Чтение строк таким способом является самым простым и наиболее эффективным, если у вас уже есть сообщение в буфере, потому что тогда вам не нужен временный буфер для строки.

Помните, однако, что с этой схемой вы должны вручную освободить память, содержащую строку, когда вы закончите со структурой.

2 голосов
/ 10 ноября 2011

Просто добавьте функцию-член, которая принимает символьный буфер (входной параметр функции char *) и заполняет структуру test, анализируя ее.
Это также делает его более понятным и читаемым.

Если вы предоставляете неявный конструктор преобразования, вы создаете угрозу, которая будет выполнять преобразование, когда вы меньше всего этого ожидаете.

0 голосов
/ 11 ноября 2011

При чтении данных переменной длины из последовательности байтов не следует помещать все в одну структуру или переменную.Указатели также используются для хранения этой переменной длины.

Следующее предложение не проверено:

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

Приветствия.

...