从 C/C++ 获取指向 msgpack 数组中元素的指针和长度

Get pointer to and length of element in msgpack array from C/C++

我有一些数据是使用 C/C++ api 使用 msgpack 打包的,如下所示:

msgpack::sbuffer sbuf;
msgpack::packer<msgpack::sbuffer> pk(&sbuf);

int var1 = 10;
std::string var2 = "test";
double var3 = 3.14159; // could be any type

pk.pack_array(3);
pk.pack(var1);
pk.pack(var2);
pk.pack(var3);

稍后我需要解压缩该数组,但需要直接访问第三个元素以便我可以坚持 file/db/redis/memcached/etc。虽然数组的前两个元素是固定类型,但第三个元素可以是 msgpack 可接受的任何类型(int、string、vector、map 等)。

size_t off = 0;
msgpack::unpacked result = msgpack::unpack(sbuf.data(), sbuf.len(), off);
msgpack::object obj = result.get();

int var1;
obj.via.array.ptr[0].convert(&var1);

std::string var2;
obj.via.array.ptr[1].convert(&var2);

// now here I want to get a pointer & len to the 3rd item so I can persist
// this value that is already msgpack'd.

const char* dataptr = reinterpret_cast<const char*>(&obj.via.array.ptr[2]);
// now what is the length of the data pointed to by dataptr?

如上所示,我可能会在 obj.via.array.ptr[2] 上执行 reinterpret_cast,但对于二进制数据或 msgpack 结构,简单的 strlen() 不会我无法获取长度,而且我看不到从哪里获取该项目的长度。我知道很多类型都有一个大小变量,但当该项目是数组或映射时,我不相信这是准确的。

这是msgpack-c的内存模型: https://github.com/msgpack/msgpack-c/wiki/v1_1_cpp_unpacker#memory-management

I know there is a size variable in many of the types but don't believe this is accurate when that item is an array or map.

没错。 obj 已经解包。不适合执着。 我认为直接存储 msgpack 格式的二进制数据是更好的方法。首先,将 msgpack 分为前两个和第三个。然后,将前两个打包为一个数组。最后,简单地打包第三个值。那就是打包过程。

    pk.pack_array(2); // for the first two
    pk.pack(var1);
    pk.pack(var2);
    pk.pack(var3);    // for the thrid one

解包时,解包前两个带偏移量的数据

    // Unpacking
    size_t off = 0;
    msgpack::unpacked result = msgpack::unpack(sbuf.data(), sbuf.size(), off);
    // off has been set

解包后,offset已经设置好了。这样就可以得到第三个数据的起点。然后,存储msgpack格式的二进制数据。

    std::string store; // file/db/redis/memcached/etc
    std::copy(sbuf.data() + off, sbuf.data() + sbuf.size(), std::back_inserter(store));

也就是存储过程。

当您从存储中获取 msgpack 格式的二进制数据时,解压缩它们。

这是一个完整的代码示例:

#include <msgpack.hpp>

#include <iostream>
#include <string>
#include <algorithm>

int main() {
    msgpack::sbuffer sbuf;
    msgpack::packer<msgpack::sbuffer> pk(&sbuf);

    int var1 = 10;
    std::string var2 = "test";
    double var3 = 3.14159; // could be any type

    // Separate the data into the two msgpacks
    pk.pack_array(2); // for the first two
    pk.pack(var1);
    pk.pack(var2);
    pk.pack(var3);    // for the thrid one

    // Unpacking
    size_t off = 0;
    msgpack::unpacked result = msgpack::unpack(sbuf.data(), sbuf.size(), off);
    msgpack::object obj = result.get();

    auto converted = obj.as<std::tuple<int, std::string>>();
    std::cout << std::get<0>(converted) << std::endl;
    std::cout << std::get<1>(converted) << std::endl;

    // Storing the thrid one
    std::cout << "off: " << off << std::endl;
    std::string store; // file/db/redis/memcached/etc
    std::copy(sbuf.data() + off, sbuf.data() + sbuf.size(), std::back_inserter(store));

    {
        // Unpack the thrid one from store
        msgpack::unpacked result = msgpack::unpack(store.data(), store.size());
        msgpack::object obj = result.get();
        if (obj.type == msgpack::type::FLOAT) {
            auto f = obj.as<float>();
            std::cout << f << std::endl;
        }
    }
}

您可以在此处检查上面代码的行为: http://melpon.org/wandbox/permlink/uFfRGKQLqnIIiDrv