Запись структуры в stringstream на языке C++
У меня есть такие структуры, как:
struct dHeader
{
uint8_t blockID;
uint32_t blockLen;
uint32_t bodyNum;
};
struct dBody
{
char namestr[10];
uint8_t blk_version;
uint32_t reserved1;
}
И у меня есть stringstream как:
std::stringstream Buffer(std::iostream::in | std::iostream::out);
Я хочу записать dHdr и несколько структур dBody в буфер с помощью
Buffer << Hdr1;
Buffer << Body1;
Buffer << Body1;
Я получаю ошибку:
Ошибка: нет соответствия для 'operator
Если я попробую с:
Buffer.write(reinterpret_cast<char*>(&Hdr1), sizeof(dbHdr1));
Buffer.write(reinterpret_cast<char*>(&Body1), sizeof(Body1));
Buffer.write(reinterpret_cast<char*>(&Body2), sizeof(Body2));
Я путаюсь в упаковке и выравнивании памяти.
- как лучше всего записать структуру в поток строк?
- и еще читать струнный поток в обычную строку?
2 ответа:
Для каждой из ваших структур вам нужно определить что-то подобное этому:
struct dHeader { uint8_t blockID; uint32_t blockLen; uint32_t bodyNum; }; std::ostream& operator<<(std::ostream& out, const dHeader& h) { return out << h.blockID << " " << h.blockLen << " " << h.bodyNum; } std::istream& operator>>(std::istream& in, dHeader& h) // non-const h { dHeader values; // use extra instance, for setting result transactionally bool read_ok = (in >> values.blockID >> values.blockLen >> values.bodyNum); if(read_ok /* todo: add here any validation of data in values */) h = std::move(values); /* note: this part is only necessary if you add extra validation above else in.setstate(std::ios_base::failbit); */ return in; }
(аналогично для других структур).
Редактировать: являются небуферизованные модули чтения/записи реализация имеет следующие недостатки:
Он неформатирован; это не может быть проблемой для небольшого служебного приложения, если вы контролируете, где оно компилируется и запускается, но обычно, если вы берете сериализованные данные и запускаете / компилируете приложение на другой архитектуре, у вас будут проблемы с endianness; вам также нужно будет убедиться, что типы, которые вы используете, не зависят от архитектуры (т. е. продолжайте использовать типы
uintXX_t
).Он хрупок; реализация зависит от структур, содержащих только типы POD. Если вы добавите символ* в свою структуру позже, ваш код будет компилироваться таким же образом, только с неопределенным поведением.
Это неясно (клиенты вашего кода ожидали бы либо увидеть интерфейс, определенный для ввода-вывода, либо предположить, что ваши структуры поддерживают нет сериализации). Обычно никто не думает: "может быть, я могу сериализовать, но используя небуферизованный ввод-вывод" - по крайней мере, не будучи клиентом пользовательской реализации структуры или класса.
Проблемыможно улучшить, добавив операторы потока ввода-вывода, реализованные в терминах небуферизованных операций чтения и записи.
Пример кода для операторов выше:
std::ostream& operator<<(std::ostream& out, const dHeader& h) { out.write(reinterpret_cast<char*>(&h), sizeof(dHeader)); return out; } std::istream& operator>>(std::istream& in, dHeader& h) // non-const h { dHeader values; // use extra instance, for setting result transactionally bool read_ok = in.read( reinterpret_cast<char*>(&values), sizeof(dHeader) ); if(read_ok /* todo: add here any validation of data in values */) h = std::move(values); /* note: this part is only necessary if you add extra validation above else in.setstate(std::ios_base::failbit); */ return in; }
Это централизует код за интерфейсом (т. е. если ваш класс больше не поддерживает без буферизации записи, вам придется изменить код в одном месте), и делает ваше намерение очевидным (реализация сериализации для вашей структуры). Она все еще хрупкая, но уже не такая.
Вы можете обеспечить перегрузку для
std::ostream::operator<<
, какstd::ostream& operator<<(std::ostream&, const dHeader&); std::ostream& operator<<(std::ostream&, const dBody&);
Дополнительную информацию смотрите в этом вопросеstackoverflow .