Как избавиться от байтов заполнения между элементами данных структуры - PullRequest
2 голосов
/ 19 июля 2010

У меня есть двоичный файл с «сообщениями», и я пытаюсь разместить байты внутри правильной переменной, используя структуры. В моем примере я использовал два типа сообщений: Tmessage и Amessage.

#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
#include <iomanip>

using namespace std;

struct Tmessage
{
    unsigned short int Length;
    char MessageType;
    unsigned int Second;
};

struct Amessage
{
    unsigned short int Length;
    char MessageType;
    unsigned int Timestamp;
    unsigned long long int OrderReferenceNumber;
    char BuySellIndicator;
    unsigned int Shares;
    char Stock[6];
    unsigned int Price;
};

int main(int argc, char* argv[])
{
    const char* filename = argv[1];
    fstream file(filename, ios::in | ios::binary);
    unsigned long long int pi = 0;

    if(file.is_open()){ cout << filename << " OPENED" << endl; }
    else { cout << "FILE NOT OPENED" << endl; }

    unsigned char* memblock;
    memblock = new unsigned char[128];
    file.read((char *)memblock, 128);

    cout <<  "BINARY DATA" << endl;
    while (pi < 128)
    {
        cout << setw(2) << hex << static_cast<unsigned int>(memblock[pi]) << " ";
        pi++;
        if((pi%16)==0) cout << endl;
    }

    unsigned int poi = 0;

    Tmessage *Trecord;
    Trecord = (Tmessage *)memblock;
    cout << "Length: " << hex << (*Trecord).Length << endl;
    cout << "Message type: " << hex << (*Trecord).MessageType << endl;
    cout << "Second: " << hex << (*Trecord).Second << endl;

    poi = poi + 7; cout << endl;

    Amessage *Arecord;
    Arecord = (Amessage *)(memblock+poi);
    cout << "Length: " << hex << (*Arecord).Length << endl;
    cout << "Message type: " << hex << (*Arecord).MessageType << endl;
    cout << "Timestamp: " << hex << (*Arecord).Timestamp << endl;
    cout << "OrderReferenceNumber: " << hex << (*Arecord).OrderReferenceNumber << endl;
    cout << "BuySellIndicator: " << hex << (*Arecord).BuySellIndicator << endl;
    cout << "Shares: " << hex << (*Arecord).Shares << endl;
    cout << "Stock: " << hex << (*Arecord).Stock << endl;
    cout << "Price: " << hex << (*Arecord).Price << endl;

    delete memblock;
    file.close();
    cout << endl << "THE END" << endl;
    return 0;
}

Вывод при запуске программы:

stream OPENED
BINARY DATA
 0  5 54  0  0 62 72  0 1c 41  0  f 42 40  0  0 
 0  0  0  4 2f 76 53  0  0  3 e8 53 50 59 20 20 
20  0 11  5 d0  0 1c 41  0  f 42 40  0  0  0  0 
 0  4 2f 78 42  0  0  3 e8 53 50 59 20 20 20  0 
10 f7 5c  0 1c 41  0  f 42 40  0  0  0  0  0  4 
2f 90 53  0  0  1 2c 53 50 59 20 20 20  0 11  2 
b0  0  5 54  0  0 62 76  0  d 44 14 25 78 80  0 
 0  0  0  0  4 2f 90  0  d 44 14 25 78 80  0  0 
Length: 500
Message type: T
Second: 726200

Length: 1c00
Message type: A
Timestamp: 40420f
OrderReferenceNumber: 53762f0400000000
BuySellIndicator: 
Shares: 20595053
Stock:   
Price: 420f0041

THE END

Программа правильно размещает байты внутри структуры Tmessage. (0 5 54 0 0 62 72)
Однако что-то происходит при разборе Amessage.
(0 1c 41 0 f 42 40 0 ​​0 0 0 0 4 2f 76 53 0 0 3 e8 53 50 59 20 20 20 0 11 5 d0)

Длина, MessageType и Timestamp верны, но OrderReferenceNumber содержит «53» байт, принадлежащий BuySellIndicator, а затем другая переменная неверна.

Правильный вывод сообщения должен быть:
Длина: 1с 0
Тип сообщения: 41
Отметка времени: 40 42 f 0
OrderReferenceNumber: 76 2f 4 0 0 0 0 0
BuySellIndicator: 53
Акции: e8 3 0 0
На складе: 53 50 59 20 20 20
Цена: d0 5 11 0

2 вопроса: а) Почему OrderReferenceNumber содержит байт "53"? б) Я думаю, что "Char Stock [6]" не работает, потому что между байтами Share и байтами Price более 6 байтов. Как я могу вписать 6 байтов в вектор символа или строку?

Примечание: я знаю, что должен поменять местами байты, потому что двоичные данные поступают в порядке с прямым порядком байтов. Вот почему «сток» не должен меняться местами. Большое спасибо за Вашу помощь! С уважением,

Ответы [ 2 ]

4 голосов
/ 19 июля 2010

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

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

Вы также должны использовать точные типы ширины, указанные в <cstdint> (Boost имеет реализацию этого заголовка, если ваша стандартная библиотека еще не имеет); это позволит вам убедиться, что размеры ваших членов данных соответствуют размерам полей в сообщении.

3 голосов
/ 19 июля 2010

Компилятор, вероятно, вставляет байты pad между членами вашей структуры.Один из способов обойти это - использовать пакет pragma.Обратите внимание, что это нестандартно, но работает на g ++ и Visual C ++.

#pragma pack (push, 1)
struct Amessage
{
    unsigned short int Length;
    char MessageType;
    unsigned int Timestamp;
    unsigned long long int OrderReferenceNumber;
    char BuySellIndicator;
    unsigned int Shares;
    char Stock[6];
    unsigned int Price;
};
#pragma pack (pop)

В приведенном выше коде происходит следующее: пакет pragma сообщает компилятору, что вы не хотите, чтобы он вставлял отступычтобы сделать так, чтобы он выполнял выравниваемый доступ к членам структуры.вещь push / pop такова, что вы можете иметь вложенные пакеты #pragma (например, при включении заголовочных файлов) и иметь возможность вернуться к ранее установленным параметрам пакета.

См. MSDN для объяснения, которое, вероятно,лучше, чем тот, который я мог дать.http://msdn.microsoft.com/en-us/library/2e70t5y1%28VS.80%29.aspx

...