У меня есть поток байтов, который мне нужно проанализировать в структуру, и мне также нужно иметь возможность анализировать структуру обратно в поток байтов.
Ниже приведен пример того, что я хочу, где я использовал BitConverter для анализа значений. Я надеюсь, что есть более эффективный способ сделать это, потому что мои структуры ОГРОМНЫ!
ref struct TestStruct
{
int TestInt;
float TestFloat;
};
int main(array<System::String ^> ^args)
{
// populating array - just for demo, it's really coming from a file
array<unsigned char>^ arrBytes = gcnew array<unsigned char>(8);
Array::Copy(BitConverter::GetBytes((int)1234), arrBytes, 4);
Array::Copy(BitConverter::GetBytes((float)12.34), 0, arrBytes, 4, 4);
// parsing to struct - I want help
TestStruct^ myStruct = gcnew TestStruct();
myStruct->TestInt = BitConverter::ToInt32(arrBytes, 0);
myStruct->TestFloat = BitConverter::ToSingle(arrBytes, 4);
String^ str = Console::ReadLine();
return 0;
}





Здесь - это объяснение сериализации в .NET.
Для общего C++ (не управляемого) посмотрите boost :: serialize
Вы упоминаете как C++, так и .net. Только для C++ вы должны иметь возможность делать что-то вроде
char buffer[sizeof(MYSTRUCT)];
memcopy((char*) &mystruct, buffer, sizeof(MYSTRUCT));
Для .net вы ДОЛЖНЫ использовать сериализацию, если вы хотите избежать сохранения каждого элемента отдельно - классы не гарантируются для сохранения в непрерывном блоке памяти. Это раздражает, но это одна из «особенностей» управляемого кода - вы должны позволить ему управлять этим за вас.
-Адам
Да! Если бы вы могли объяснить, как это сделать в NET с управляемыми типами ссылок.
Вы не можете. Вы должны сохранить каждую позицию отдельно или использовать сериализацию.
Могу ли я с помощью сериализации определить, каким должен быть выходной двоичный формат, без сохранения каждого элемента отдельно / вручную?
Для подобных вещей вы обычно используете генератор кода. Предположим, исходник выглядит так:
struct a {
int i;
}
struct b {
string name;
struct a a;
}
Что вы делаете, так это пишете простой синтаксический анализатор, который ищет в источнике (возможно, в каком-то заголовочном файле) слово «структура», затем вы читаете имя структуры (любое значение между «структура» и «{»). Напишите это на выходе:
cout << "struct " << name << " * read_struct_" << name << " (stream in) {" << NL
<< " struct " << name << " * result = malloc (sizeof(struct " << name << "));" NL
parseFields (headerStream);
cout << " return result;" << NL << "}" << NL ; }
Обратите внимание, что мой C++ немного ржавый, поэтому он, вероятно, не компилируется, но вы должны понять.
В parseFields вы читаете каждую строку и разделяете ее на две части: все, что находится перед последним пробелом (например, «int» в первом примере) и что-то между последним пробелом и и «;». В данном случае это будет «i». Теперь вы пишете на выход:
cout << "read_" << fieldType << "(in, &result->" << fieldName << ");" << NL;
Примечание. Вам нужно будет заменить все пробелы ub в типе поля на "_".
На выходе это выглядит так:
struct a * read_struct_a (stream in) {
struct a * result = malloc(sizeof(struct a));
read_int(in, &result->i);
return result;
}
Это позволяет вам определить, как читать или записывать int где-нибудь еще (в служебном модуле).
Теперь у вас есть код, который считывает определения структуры из файла заголовка и создает новый код, который может считывать структуру из некоторого потока. Дублируйте это, чтобы записать структуру в поток. Скомпилируйте сгенерированный код, и все готово.
Вы также захотите написать модульные тесты, чтобы убедиться, что синтаксический анализ работает правильно :) Просто создайте структуру в памяти, используйте методы записи, чтобы сохранить ее где-нибудь и прочитать ее снова. Теперь две структуры должны быть идентичными. Вам нужно будет написать третий генератор кода для создания кода для сравнения двух структур.
Вам нужно будет объяснить это подробнее. Структуры идентичны исходному формату, и я не контролирую источник (или формат).
Сериализация - это здорово, но в моем случае мне не нужны «дополнительные услуги», и мне все равно придется проделывать ту же работу, чтобы иметь полный контроль над битами. Думаю, для большинства это могло быть решением.
Дать г-ну Дигулле правильный ответ, так как он больше всего напоминает мое решение. Также спасибо мистеру Дэвису, который объяснил мне, что это нужно сделать ...
Как форматируется двоичный формат, уже определено. Это подводит меня к настраиваемой сериализации и возвращает ту же проблему. Несколько сотен строк с BitConverter, или есть способ получше?