Чтение сериализованных структур C ++ в C # с использованием BinaryReader - PullRequest
2 голосов
/ 27 марта 2012

У меня есть несколько файлов, которые были сериализованы путем непосредственной записи C ++ struct s с использованием двоичного файла fstream. Теперь, когда я генерирую методы чтения для соответствующих классов C #, я обнаруживаю, что они на самом деле не отображаются 1-к-1, возможно, из-за упаковки структуры.

Итак, мой вопрос - как лучше всего справиться с ситуацией? У меня есть исходный код на C ++ и C #, поэтому я могу изменить любую часть. Должен ли я попытаться сериализовать C ++ без упаковки (я предполагаю, что это делается с помощью #pragma pack(1), верно) или вместо этого каким-то образом настроить мой код C # для учета пробелов?

Или проблема с десериализацией совершенно другая и не имеет ничего общего с упаковкой?

Обновление 1 Я обнаружил, что C ++ enum s имеет длину 4 байта и bool значения имеют длину 2 байта (кто знал?), Но даже после добавления #pragma pack(1) я могу только правильно прочитал первую запись. Кроме того, я проверил количество байтов против sizeof(MyStructure) и совпадения значений. Это должно означать, что между записями есть некоторый отступ.

Обновление 2 Черт, обнаружена ошибка в коде. Ошибка копирования-вставки. Нужна PVS Studio или что-то в этом роде. Все хорошо сейчас. (И да, логическое значение имеет размер 1 байт.)

1 Ответ

2 голосов
/ 27 марта 2012

Выравнивание является вероятной причиной проблемы.

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

Если вам нужно надежно обмениваться структурами, было бы лучше #pragma pack(1) и добавить заполнение обратно вручную, если производительность является проблемой. Это может быть проблемой, только если структуры используются в узком внутреннем цикле.

Пример ручного выравнивания:

struct Record {
    char c;
    char __padding[7];
    double d;
};

Ваш код на C # будет выглядеть примерно так:

this.c = reader.ReadChar();
reader.ReadBytes(7); // or reader.BaseStream.Seek(7, SeekOrigin.Current);
this.d = reader.ReadDouble();
...