0

在我必须维护的代码中,一些数组序列化(例如std::vector<T>)大致按以下方式发生:有一个array_t没有填充的结构:

#pragma pack(push, 1)
template <typename T, uint32_t N>
struct array_t
{
    typedef T value_type;
    static uint32_t const max_length = N;

    uint32_t length;
    value_type data[max_length];

    value_type const & operator[](uint32_t k) { return data[k]; }
    value_type & operator[](uint32_t k) { return data[k]; }

    template <typename Container>
    void from_container(Container const & c)
    {
        std::copy(c.begin(), c.end(), &(*this)[0]);
        length = c.size();
    }

    template <typename Container>
    Container to_container() const
    {
        return Container(&(*this)[0], &(*this)[length]);
    }
};
#pragma pack(pop)

当需要通过网络发送此类数据类型时,会发生什么(非常简化):

template <typename T>
char * serialize(T const & data)
{
    void * buf = std::malloc(sizeof(T));
    std::memcpy(buf, &data, sizeof(T));
    return reinterpret_cast<char *>(buf);
}

std::string const s("This is some string");
typedef array_t<char, 64> arr_str;
arr_str serial;
serial.from_container(s);
char * buf = serialize(serial);
network.send(buf); // frees the memory as well

而在另一端,这个方法被称为:

template <typename T>
T deserialize(char * ptr)
{
    T data;
    std::memcpy(&data, ptr, sizeof(T));
    std::free(ptr);
    return data;
}

arr_str deserial = deserialize<arr_str>(buf);

我们不需要争辩说这不是序列化对象的最佳方式。我现在关心的是:它的便携性如何?这些方法的评论说这可以保证在每个 x86/x64 系统上都有效——这是真的吗?

4

2 回答 2

2

这绝对不能移植到“任何 x86”架构,除非您非常注意在您正在使用的所有数据结构中仅使用定义大小(uint16_tuint32_t等)的类型。

显然,如果您不使用 x86 系列处理器,那么您将遇到字节排序的进一步问题。

于 2013-08-22T12:41:09.880 回答
0

你的问题很模糊。如果发送和接收是同一个二进制文件,并且数据类型 T 是 POD,那么这将起作用。

如果使用不同的二进制文件 - 使用不同的编译器、编译器版本、编译器设置等进行编译,那么数据类型的简单类型和简单结构可能是可以的(编译时 offset_of 和 sizeof 断言值得考虑),但很多事情没有指定按照标准,包括位字段的排序和填充方式(特别是当它们跨越 8/16/32 位边界时)、布尔值和枚举的大小(除非根据 C++11 指定)。许多标准库类型的布局也没有指定,因此即使您知道发送者和接收者都对所涉及的字符串大小使用短字符串优化,您也不能假设说 std::string 会在传输中幸存下来.

于 2013-08-22T12:50:24.530 回答