如果我布置结构的字段以便它们不需要任何填充,那么一致的C ++编译器是否可以添加额外的?

时间:2015-01-14 22:28:39

标签: c++ struct

我想用C ++格式化现有二进制协议格式的数据包(我正在编写一个memcached客户端)。在C中,我可以这样做:

    typedef struct {
        uint8_t magic;
        uint8_t opcode;
        uint16_t keylen;
        uint8_t extlen;
        uint8_t datatype;
        uint16_t reserved;
        uint32_t bodylen;
        uint32_t opaque;
        uint64_t cas;
    } request_header;

在C ++中,通常,编译器可以在字段之间添加填充。但是,上面的结构是经过精心布局的,因此所有内容都可以在没有填充的情况下对齐,假设n位类型只需要在n位边界上对齐。所以在C ++中,根据标准,我安全吗?或者一个符合标准的C ++编译器是否可以添加额外的填充,阻碍我使用它来布置我的位?

3 个答案:

答案 0 :(得分:6)

这不值得烦恼,只是让编译器告诉你这很奇怪:

  static_assert(sizeof(request_header) == 24, "Unexpected packet size");

答案 1 :(得分:4)

你是对的,C ++可以任意填充。从C ++。11§9.2¶14(重点是我的):

  

分配具有相同访问控制(第11条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。未指定具有不同访问控制的非静态数据成员的分配顺序(11)。 实施对齐要求可能导致两个相邻成员不能立即分配;所以可能需要空间来管理虚函数(10.3)和虚基类(10.1)。

C也允许添加填充字节,因此这不是C ++特有的。从C.11§6.7.2.1¶15(重点是我的):

  

在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址。指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 结构对象中可能有未命名的填充,但不是在开头。

如果要避免填充,唯一最便携的方法是在发送时将数据结构自己打包到连续的内存中(例如,vector),并在接收时将序列化数据解压缩到数据结构中。您的编译器可能提供扩展,允许您将所有成员保留在struct连续的(例如,GCC的packed属性或VC ++的pack编译指示中,如here所述。 / p>

答案 2 :(得分:1)

在C ++中有这样的东西称为POD,用于普通旧数据。基本上,如果满足某些限制,C ++中的结构就是POD,它将与C代码中定义的相同结构进行字节到字节的兼容。

要成为POD,结构必须没有访问说明符(public,private),并且没有非静态成员函数,包括运算符,构造函数和析构函数。