MessagePack C API
Рассматривая C API для MessagePack, существует ряд функций для соответствующей сериализации (упаковки) данных в соответствии с типом: msgpack_pack_uint8
, msgpack_pack_int32
...
Похоже, в API нет аналогичного вызова для распаковки данных. msgpack_unpack_next
возвращает msgpack_object
, Эти объекты имеют только грубую гранулярность типов (самый большой из типов: int64, double, ...), основываясь на включенных перечислениях.
Я что-то здесь упускаю? Является ли ожидание, что грубый объект будет использован, а затем приведен?
Как правильно распаковывать вещи?
Кроме того, есть ли хорошая документация или примеры использования? Те, что на сайте, тривиальны.
1 ответ
Во время распаковки любое целочисленное значение всегда сохраняется в msgpack_object
как 64-разрядное целое число фиксированной ширины (int64_t
если отрицательный, uint64_t
иначе).
Увидеть cpp/src/msgpack/object.h
для более подробной информации о msgpack_object
и др., и cpp/src/msgpack/unpack.c
чтобы увидеть, как msgpack обрабатывает логику распаковки, например:
static inline int template_callback_int8(unpack_user* u,
int8_t d,
msgpack_object* o) {
if(d >= 0) {
o->type = MSGPACK_OBJECT_POSITIVE_INTEGER; o->via.u64 = d;
return 0;
}
else {
o->type = MSGPACK_OBJECT_NEGATIVE_INTEGER; o->via.i64 = d;
return 0;
}
}
Это связано с тем, что во время упаковки msgpack динамически выбирает наиболее оптимальный способ кодирования целого числа в соответствии с его значением, например, если вы используете msgpack_pack_uint16
чтобы упаковать ваше целое число:
- оно будет сохранено в 1 байте, если значение находится в [0, 127],
- 2 байта с
0xcc
в качестве первого байта, если значение находится в [128, 255], - 3 байта с
0xcd
как первый байт в противном случае.
Увидеть msgpack_pack_real_uint16
от cpp/src/msgpack/pack_template.h
Больше подробностей.
Другими словами, во время распаковки msgpack использует достаточно большой положительный или отрицательный результат (проверьте, obj.type
является MSGPACK_OBJECT_POSITIVE_INTEGER
или же MSGPACK_OBJECT_NEGATIVE_INTEGER
) для хранения любого целочисленного значения. Так что вам решать:
- приведение, если вы всегда можете предположить, что значения никогда не будут превышать ваш тип приведение,
- или, динамически (с маской) проверить, является ли значение недостаточно большим для вашего типа получателя,
- или всегда используйте
int64_t
или жеuint64_t
,
Наконец, тестовый набор C (msgpack/cpp/test/msgpackc_test.cpp
) может быть полезно просмотреть примеры кода.