Хранение структуры данных в файловой системе


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

Например, я бы задал линейный блок памяти в качестве структуры данных (используя ключевое слово new), а затем описал, что означает первый байт, что означает второй байт и так далее. Я знаю, что я ... можно сделать это с помощью struct, но тогда структура данных будет привязана к одному языку,и другие языки должны будут использовать эту структуру. Кроме того, реализация может изменяться от компилятора к компилятору. Я бы предпочел, чтобы это был стандарт памяти. Является ли то, что я пытаюсь сделать, чем-то разумным? Или я пытаюсь чрезмерно упростить вещи и действительно должен перейти к структуре данных struct? Теперь перейдем к части C++, если вы считаете, что я должен использовать структуру данных struct, то каковы недостатки использования полноценного класса?

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

2 3

2 ответа:

Несколько форматов файлов, с которыми я читал/работал, делают именно это-определяют стандарт памяти или макет, а затем обычно создают его резервную копию с демонстрацией в C-like pseudo - structure. Иногда они предоставляют представления структур или классов, а некоторые полностью абстрагируются библиотекой. Конечно, эти форматы позволяют документировать все поля, их размеры, конечность данных и так далее.

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

Следуя этим маршрутом:

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

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

Одна из важных частей заключается в том, что у вас должны быть тесты, которые подтверждают, что ваш граф объектов в памяти, который вы создаете с помощью этих структур, является прямым и обратным сериализуемым и десериализуемым, и поддерживают правильное управление версиями-поэтому часто требуется немного работы, чтобы сделать сложное сериализованное представление совместимым. Таким образом, вы видите, что этот подход просто вводит один слой абстракции поверх другого. В связи с этим вы можете захотеть дать C++ абстракция способность создавать себя из упакованного в памяти представления и гарантировать, что это представление может также правильно заполнить упакованную структуру без потери данных.

Помимо этого, есть ли какая-либо необходимость иметь более продвинутый интерфейс? Если есть, то вы можете предоставить эту информацию.

Так что да, стандарт памяти-это та часть, которую вы должны получить правильно и стабильно, и к которой все реализации должны ссылаться и тестировать против -- независимо от различий между платформой и архитектурой. IOW, вы на правильном пути;)

В C++ нет никакой практической разницы между struct и class (Кроме того, доступность по умолчанию является общедоступной в struct). Традиционно struct используется, когда тип имеет только (открытые) переменные-члены и не имеет функций-членов, но это только соглашение, а не правило, применяемое компилятором.

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

Я рекомендую вам начать свою структуру примерно так:

typedef struct
{
    int Version; // struct layout version
    int ByteSize; // byte size of structure for validation
    ...
} MYDATA;

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

Когда вы сохраняете данные на диск, убедитесь, что вы записываете их поле за полем, а не через одну запись (используя указатель и sizeof(), чтобы гарантировать, что другим языкам не придется иметь дело с потенциальным заполнением, которое ваш компилятор C++ может решить вставить. Можно вручную расположить поля в структуре так, чтобы не было заполнения, но при этом нужно быть очень, очень осторожным, и легко ошибиться.