对于没有填充的结构,依赖sizeof是多么的便携

How portable is relying on sizeof for structures without padding

本文关键字:sizeof 于没 填充 结构 依赖      更新时间:2023-10-16

在我必须维护的代码中,一些数组序列化(例如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系统-是那说法是真的吗?

这绝对不能移植到"任何x86"体系结构,除非您非常小心地在所有使用的数据结构中只使用定义大小的类型(uint16_tuint32_t等)。

显然,如果您超出了x86系列处理器,那么您将面临字节排序的进一步问题。

你的问题很含糊。如果相同的二进制进行传输和接收,并且数据类型T是POD,那么这将起作用。

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