我想用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 ++编译器是否可以添加额外的填充,阻碍我使用它来布置我的位?
答案 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),并且没有非静态成员函数,包括运算符,构造函数和析构函数。