LINUX.ORG.RU

Сериализация данных в plain C

 ,


1

2

Как нынче модно в plain C выполнять сериализацию/десериализацию данных?

Ну то есть у меня какая-то структура, я хочу её записать в файл/отправить по сети. Значит мне нужно:

- Убрать выравнивание

- Переставить байтики под endiness (если не совпадает с endiness сериализации)

- Сделать то же самое для вложенных структур

- Вытащить динамические массивы (в самой структуре представлены двумя полями - длина и первый элемент) из кучи и положить их линейно с остальными полями

То есть прожиточный минимум - это либа, которая работает с байтовым буфером и имеет функции вида buffer_write_int8/buffer_write_int16/buffer_write_float32/buffer_read_int32/etc. Но если бы было можно пропарсить заголовочник с используемыми структурами (для меня ок, если будет требование все сериализуемые структуры держать в отдельных заголовочниках) и сгенерировать сериализаторы, либо наоборот сгенерировать структуры и сериазаторы из описания в каком-то другом формате, то было бы вообще шикарно.

Что я не хочу? Не хочу никакого оверхеда и метаинформации в сериализованных данных. Если я сериализую структуру из 3 int32_t, значит выходной буфер должен иметь размер строго 12 байт. Максимум можно опциональную фичу, отдельно включаемую для определённых структур, чтобы перед структурой писался её размер (типа чтобы при попытке десериализации старой версии структуры, новые поля проинициализировались нулями - подразумевается, что поля могут быть добавлены только в конец). Но я и без неё отлично проживу. И обязательно опциональная фича (потому что некоторые структуры точно не изменятся).

Так что всякие Protobuf не подходят, потому что помимо самих данных пишут всякую метаинформацию.

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

★★★★★

Последнее исправление: KivApple (всего исправлений: 2)

Так что всякие Protobuf не подходят, потому что помимо самих данных пишут всякую метаинформацию.

Наш человек! =) Напиши своё, не бог весть какая проблема. У меня API примитивное: read/write(int16_t), (int32_t), (const char*), … И сериализация каждой структуры выполняется вручную (псевдокод C++ like, я хз как там правильно полагается на сях):

void serialize(binostream& os, LoginStruct x) {
    os.write(1);   // версия, если угодно.
    os.write(x.login);
    os.write(x.password);
}

Десериализация – точно также руками в лоб.

Любая попытка «автоматизировать» этот предельно тупой подход – через рефлексию там или ещё как, даже на жаве (где дохерища всяких говнорешений, сериализующих через рефлексию) приведёт лишь к усложнению, утяжелению засериализованного формата, и потере твоего контроля над ситуацией. Зуб даю.

UPD. Ну на сях, без оверлоадед, я бы сделал функции void write_i16(os, int16_t) / int16_t read_i16(is) и т.п.

Credit goes to: Apache Wink (давным-давно всеми забытый JSON serializer, в силу засилья жаваскриптомакак).

dimgel ★★★★★
()
Последнее исправление: dimgel (всего исправлений: 3)
Ответ на: комментарий от beastie

Я нашёл корень проблемы - это всё от того, что в protobuf-c CMake скрипте используется CMAKE_BINARY_DIR вместо CMAKE_CURRENT_BINARY_DIR, хотя по идее если нет серьёзной причины, надо всегда использовать второй. Из-за этого ломается сборка через add_subdirectory.

Создал Pull-реквст:

https://github.com/protobuf-c/protobuf-c/pull/482

KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.