有没有办法控制C++中结构成员(包括位字段)之间的填充?

Zij*_*gWu 12 c c++ padding

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

例如,我想如下定义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;
   .....
};
Run Code Online (Sandbox Code Playgroud)

并以这种方式使用它.

RTPHeader header;
memcpy(&header, steamData, sizeof(header));
Run Code Online (Sandbox Code Playgroud)

但是,由于C++编译器将在成员之间插入填充,有没有办法控制它,以便在成员之间不添加填充(包括位字段成员)?

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

Pap*_*ter 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!
Run Code Online (Sandbox Code Playgroud)

如果您选择的是MSVC,则必须将该pragma放在struct 之前:

#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;
    .....
};
Run Code Online (Sandbox Code Playgroud)

如果您的代码必须同时编译,唯一的方法(没有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
Run Code Online (Sandbox Code Playgroud)


Mat*_*son 3

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

 #pragma(pack)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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