簡體   English   中英

有沒有辦法控制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放在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;
    .....
};

如果您的代碼必須同時編譯,唯一的方法(沒有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

為避免插入填充字節,您可以使用

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

typedef struct {...}MY_STRUCT;

#pragma pack(pop)

這對我來說很好。

還要考慮Struct Member Alignment的編譯選項

/Zp1

但請記住,這會對整個項目產生影響。

只要你沒有要求這個代碼在任意機器上“工作” - 例如對int所在的字節邊界(通常是4字節邊界)有限制的機器,那么使用

 #pragma(pack)

應該工作,它在GCC以及Microsoft和“Microsoft插件兼容”編譯器(例如Intel的編譯器)中得到支持。

但請注意,並非所有處理器都支持未對齊訪問,因此啟動具有16位值的塊,然后是32位int可能會導致問題。

我還會對sequencenumber使用一個大小的整數來確保它在每個編譯器中都是32位,而不是突然的16位或64位。

另請注意,C ++標准沒有說明位存儲在位域中的順序 - 或者說它們之間是否存在間隙。 雖然你可以期望根據字節順序存儲位域(小端機器首先從最低位開始,大端機器首先從最高位開始),但標准在這方面沒有說明任何內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM