有没有办法控制C++中结构成员(包括位字段)之间的填充
Is there any way to control the padding between struct members (incl. bit field) in C++?
我正在解析网络数据流,我想知道是否有任何方法可以将数据流直接映射到数据结构。
例如,我想定义 RTP 协议的数据结构,如下所示。
class RTPHeader
{
int version:2; // The first two bits is version.
int P:1; // The next bits is an field P.
int X:1;
int CC:4;
int M:1;
int PT:7;
int sequenceNumber;
int64 timestamp;
.....
};
并以这种方式使用它。
RTPHeader header;
memcpy(&header, steamData, sizeof(header));
但是,由于C++编译器将在成员之间插入填充,因此有没有办法控制它,以便在成员(包括位字段成员)之间不添加填充?
这个问题不是如何摆脱结构的数据成员之间的填充字节的副本,因为我的示例中可能有位字段。
如果能够使用 C++11,则可以利用使用 alignof
运算符实现的对齐控件。
如果您不能使用 C++11 编译器,有一些非标准的替代方案可以帮助您; 在 GCC 中是__attribute__(packed)
,而 MSVC 是#pragma pack
。
如果您选择的是 GCC 变体,则必须将属性放在结构的末尾:
class RTPHeader
{
int version:2; // The first two bits is version.
int P:1; // The next bits is an field P.
int X:1;
int CC:4;
int M:1;
int PT:7;
int sequenceNumber;
int64 timestamp;
.....
} __attribute__((packed)) ; // attribute here!
如果您选择的是 MSVC 选项,则必须将杂注放在结构体之前:
#pragma pack(1) // pragma here!
class RTPHeader
{
int version:2; // The first two bits is version.
int P:1; // The next bits is an field P.
int X:1;
int CC:4;
int M:1;
int PT:7;
int sequenceNumber;
int64 timestamp;
.....
};
如果代码必须同时编译,唯一的方法(没有 C++11 alignof
运算符)是条件编译:
#ifdef MSVC
#pragma pack(1)
#endif
class RTPHeader
{
int version:2; // The first two bits is version.
int P:1; // The next bits is an field P.
int X:1;
int CC:4;
int M:1;
int PT:7;
int sequenceNumber;
int64 timestamp;
.....
#ifdef GCC
}__attribute__((packed));
#else
};
#endif
只要你不要求此代码在任意机器上"工作"——例如,对int
所在的字节边界有限制的机器(通常是 4 字节边界),那么使用
#pragma(pack)
应该可以工作,并且在 GCC 以及Microsoft和"Microsoft插件兼容"编译器(例如英特尔的编译器)中受支持。
但请注意,并非所有处理器都支持未对齐的访问,因此以 16 位值启动块,然后是 32 位int
可能会导致问题。
我还会对序列号使用一个大小的整数,以确保它在每个编译器中都是 32 位,而不是突然的 16 或 64 位。
另请注意,C++标准没有说明位存储在位域中的顺序 - 或者就此而言,它们之间是否存在间隙。尽管您可以期望根据字节顺序存储位域(小端序计算机首先从最低位开始,大端序计算机首先从最高位开始),但标准在这方面没有说明任何内容。
要避免插入填充的字节,您可以使用
#pragma pack(push,n) // use n = 1 to have 1 Byte resolution
typedef struct {...}MY_STRUCT;
#pragma pack(pop)
这对我来说很好用。
还要考虑结构成员对齐的编译选项
/Zp1
但请记住,这将对您的整个项目产生影响。
- 将位字段导出到数组
- 在java中读取c++字节的位字段
- C++内存模型和位字段的最大序列
- 如何在QByteArray中放置和检索位字段而不会感到痛苦?
- 如何通过UDP接收QByteArray并将其解析为位字段结构?
- 如何使用位字段将数据从二进制文件复制到结构中?
- sizeof 函数如何在带和不带位字段的结构上工作?(填充)
- 预 C++20 位字段零初始化
- 无法初始化以 std::byte 作为成员类型的位字段
- 与位字段的并集为位字段成员提供了意外值
- 哪些是互斥的:位字段还是格式化标志?在c++中
- 位字段附近的变量会损坏吗?
- 如何将 32 位无符号整数分配给包含 32 位的位字段
- 在结构中使用位字段并使用C++从内存中读取实例
- MEMCMP以相同(零值)位字段结构返回非零
- 使用固定大小类型时强制对位字段(C++14 之前)进行签名
- 返回对位字段的访问类型
- 两个 4 位位字段加起来不等于一个字节的大小 - 如何修复?
- 为什么使用最大位字段序列定义C++内存?
- 有没有办法控制C++中结构成员(包括位字段)之间的填充