问题
I'm working on parsing network data stream, I'm wondering if there is any way I can map the data stream directly to the data structure.
For example, I want to define the data structure for an RTP protocol as follows.
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;
.....
};
And using it this way.
RTPHeader header;
memcpy(&header, steamData, sizeof(header));
But as the C++ compiler will insert padding between the members, is there any way to control that so that no padding are added between members (including the bit field members)?
This question is NOT a duplicate of How to get rid of padding bytes between data members of a struct because there can be bit fields in my example.
回答1:
As long as you have no requirement that this code "works" on arbitrary machines - e.g. machines that have restrictions as to what byte boundaries an int sits on (typically a 4 byte boundary), then using
#pragma(pack)
should work, and it's supported in GCC as well as Microsoft and "Microsoft plug in compatible" compilers (Such as Intel's compiler).
But do note that unaligned access is not supported on all processors, so starting a block with a 16-bit value, followed by a 32-bit int is possibly going to cause problems.
I would also use a sized integer for sequencenumber to ensure it's 32-bits in EVERY compiler, and not suddenly 16 or 64 bits.
Note also that the C++ standard does not state anything about the order that the bits are stored in a bitfield - or for that matter if there are gaps between them or not. Although you can expect the bitfields to be stored according to the byte-order (little endian machines start with the lowest bits first, big endian machines start with the highest order bits first), the standard does not state anything in that respect.
回答2:
If you're able to use C++11, you can take advantage of the align control implemented with the alignof operator.
If you cannot use a C++11 compiler, there's non-standard alternatives that can help you; in GCC the __attribute__(packed), and with MSVC the #pragma pack.
If your choice is the GCC variant, the attribute must be placed at the end of the struct:
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!
If your choice is the MSVC one, the pragma must be placed before the 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;
.....
};
If your code must be compiled in both, the only way (without C++11 alignof operator) is the conditional compilation:
#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
回答3:
To avoid an insertion of padded bytes you can use
#pragma pack(push,n) // use n = 1 to have 1 Byte resolution
typedef struct {...}MY_STRUCT;
#pragma pack(pop)
This worked fine for me.
Also consider the compiling options for Struct Member Alignment
/Zp1
But keep in mind that this will have an impact to your whole project.
来源:https://stackoverflow.com/questions/18653110/is-there-any-way-to-control-the-padding-between-struct-members-incl-bit-field