Могу ли я сделать одну двоичную запись для структуры C ++, которая содержит вектор

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

Писать верхний и нижний колонтитулы хорошо, так как они имеют фиксированный размер, но я сталкиваюсь с проблемами со структурой «Детали» из-за вектора. На данный момент я пишу в файл, чтобы я мог проверить запрос, чтобы специфицировать, но намерение состоит в том, чтобы написать в ПЛК с использованием последовательного порта boost asio в конце концов

Я могу использовать синтаксис так, чтобы написать структуру, но она записывает адреса указателя, а не значения, когда он попадает в вектор

myFile.write((char*) &myDataRequest, drSize);

Я могу использовать этот синтаксис для написания вектора самостоятельно, но я должен включить индексатор в 0, чтобы записать значения

myFile.write((char*) &myVector[0], vectorSize);

Есть ли элегантный способ написать двоичную структуру, содержащую вектор (или другую подходящую коллекцию), делая это за один раз? Скажем, например, если я объявил вектор по-другому, или я смирился с выполнением нескольких записей для содержимого внутри структуры. Если я заменю вектор массивом, я могу отправить структуру за один раз (без необходимости включать какой-либо индексатор), но я не знаю требуемый размер до времени выполнения, поэтому я не думаю, что он подходит.

Моя структура

    struct Header
{   ...     };

struct Details
{
std::vector<DataRequest> DRList;
};

struct DataRequest
{
short numAddresses;          // Number of operands to be read   Bytes 0-1
unsigned char operandType;   //                                  Byte 2
unsigned char Reserved1;     //Should be 0xFF                    Byte 3
std::vector<short> addressList;  // either, starting address (for sequence), or a list of addresses (for non-sequential)
};

struct Footer
{   ...     };

1

Решение

Это невозможно, потому что std::vector Объект на самом деле не содержит массив, а указатель на блок памяти. Тем не менее, я испытываю соблазн утверждать, что возможность писать необработанную структуру подобным образом нежелательна:

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

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

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

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

2

Другие решения

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

Если вы хотите удобство маршаллинга / демаршаллинга, вам стоит взглянуть на повышение :: сериализации библиотека. Они предлагают бинарный архив (помимо текста и xml), но он имеет свой собственный формат (например, у него есть номер версии, какая библиотека сериализации использовалась для выгрузки данных), так что это, вероятно, не то, что хочет ваш клиент.

1

Какой именно формат ожидается на другом конце? Вы должны написать
это, период. Вы не можете просто написать произвольные байты. Вероятность
что просто написание std::vector как вы делаете, работа о
как можно ближе к 0, как вы можете получить. Но вероятность того, что написание
struct только с int будет работать еще менее 50%. Если другой
сторона ожидает определенную последовательность байтов, то вы должны написать
эта последовательность, побайтово Написать intНапример, вы должны
по-прежнему записывать четыре (или что требует протокол) байта, что-то
лайк:

byte[0] = (value >> 24) & 0xFF;
byte[1] = (value >> 16) & 0xFF;
byte[2] = (value >>  8) & 0xFF;
byte[3] = (value      ) & 0xFF;

(Даже здесь, я полагаю, что ваше внутреннее представление отрицательного
номера соответствуют номерам протокола. Обычно бывает, но не так
всегда.)

Обычно, конечно, вы строите свой буфер в std::vector<char>,
а потом написать &buffer[0], buffer.size(), (Тот факт, что вам нужно
reinterpret_cast указатель буфера должен сигнализировать, что ваш
подход неправильный.)

1
По вопросам рекламы [email protected]