12

我正在解析网络数据流,我想知道是否有任何方法可以将数据流直接映射到数据结构。

例如,我想为 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++ 编译器将在成员之间插入填充,有没有办法控制它以便在成员之间不添加填充(包括位字段成员)?

这个问题不是如何摆脱结构数据成员之间的填充字节的重复,因为在我的示例中可能存在位字段。

4

3 回答 3

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 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++11alignof运算符)是条件编译:

#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
于 2013-09-06T09:20:26.990 回答
3

为避免插入填充字节,您可以使用

#pragma pack(push,n)   // use n = 1 to have 1 Byte resolution

typedef struct {...}MY_STRUCT;

#pragma pack(pop)

这对我来说很好。

还要考虑 Struct Member Alignment 的编译选项

/Zp1

但请记住,这将对您的整个项目产生影响。

于 2013-09-06T08:46:53.760 回答
3

只要您不要求此代码在任意机器上“工作” - 例如机器对所int坐的字节边界有限制(通常是 4 字节边界),然后使用

 #pragma(pack)

应该可以工作,并且它在 GCC以及 Microsoft 和“Microsoft 插件兼容”编译器(例如 Intel 的编译器)中都受支持。

但请注意,并非所有处理器都支持非对齐访问,因此以 16 位值开始一个块,然后是 32 位int可能会导致问题。

我还会为序列号使用一个大小整数,以确保它在每个编译器中都是 32 位,而不是突然变成 16 位或 64 位。

另请注意,C++ 标准没有说明位存储在位域中的顺序 - 或者就此而言,它们之间是否存在间隙。尽管您可以期望按照字节顺序存储位域(小端机器首先从最低位开始,大端机器首先从最高位开始),但该标准在这方面没有说明任何内容。

于 2013-09-06T09:12:46.513 回答