我正在解析网络数据流,我想知道是否有任何方法可以将数据流直接映射到数据结构。
例如,我想如下定义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 ++编译器会在成员之间插入填充,有没有办法控制它,以便在成员之间不添加填充(包括位字段成员)?
此问题与How to get rid of padding bytes between data members of a struct不重复,因为我的示例中可能有位字段。
答案 0 :(得分:8)
如果您能够使用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:
#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
答案 1 :(得分:3)
为避免插入填充字节,您可以使用
#pragma pack(push,n) // use n = 1 to have 1 Byte resolution
typedef struct {...}MY_STRUCT;
#pragma pack(pop)
这对我来说很好。
还要考虑Struct Member Alignment的编译选项
/Zp1
但请记住,这会对整个项目产生影响。
答案 2 :(得分:3)
只要您不要求此代码在任意机器上“起作用” - 例如对int
所在的字节边界(通常为4字节边界)有限制的机器,然后使用
#pragma(pack)
应该可以工作,它是supported in GCC以及Microsoft和“Microsoft plug in compatible”编译器(例如Intel的编译器)。
但请注意,并非所有处理器都支持未对齐访问,因此启动具有16位值的块,然后是32位int
可能会导致问题。
我还会对sequencenumber使用一个大小的整数来确保它在每个编译器中都是32位,而不是突然的16位或64位。
另请注意,C ++标准没有说明位存储在位域中的顺序 - 或者说它们之间是否存在间隙。虽然你可以期望根据字节顺序存储位域(小端机器首先从最低位开始,大端机器首先从最高位开始),但标准在这方面没有说明任何内容。