C++ 使用c+解包位字段+;产生错误的结果

C++ 使用c+解包位字段+;产生错误的结果,c++,bit-fields,C++,Bit Fields,我正在尝试使用位域解压mp3帧 mp3帧的标头以同步字0xFFF开头,后跟20位标头数据。标题的结构表示如下: struct Mp3FrameRaw { unsigned short fff:12; // Should always be 0xFFF = 4095 unsigned short mpeg_standard : 1; unsigned short layer : 2; unsigned short error_protection : 1; unsigned s

我正在尝试使用位域解压mp3帧

mp3帧的标头以同步字0xFFF开头,后跟20位标头数据。标题的结构表示如下:

struct Mp3FrameRaw {
  unsigned short fff:12; // Should always be 0xFFF = 4095
  unsigned short mpeg_standard : 1;
  unsigned short layer : 2;
  unsigned short error_protection : 1;
  unsigned short bitrate : 4;
  unsigned short frequency : 2;
  unsigned short pad_bit : 1;
  unsigned short  : 1;
  unsigned short mode :2;
  unsigned short mode_extension :2;
  unsigned short copyrighted : 1;
  unsigned short original: 1;
  unsigned short emphasis: 2;
};
报头的总长度为32位

我的程序首先找到同步字:

size_t find_sync_word(std::vector<unsigned char> & input) {
  bool previous_was_ff = false;

  for (size_t offset = 0; offset < input.size(); ++offset) {
    if (previous_was_ff && (input[offset] & 0xF0 == 0xF0))
      return offset - 1;
    previous_was_ff = 0xFF == input[offset];
  }
  return -1;
}
结果如下:

3071 (Should always be 4095)
3 (Should be 1 )
0 (Should be 1 - 14)
相反,如果我一点一点地手动解压缩字段,那么一切都会按预期进行。e、 g

{
    size_t offset;
    Mp3FrameRaw frame;        
    ...

    frame.fff = input[offset++];
    frame.fff = (frame.fff << 4) | (input[offset] >> 4);

    frame.mpeg_standard = (input[offset] >> 3) & 1;
    frame.layer = (input[offset] >> 1) & 0x3;
    frame.error_protection = (input[offset++]) & 0x1;
    frame.bitrate = input[offset] >> 4;
    ...

}
{
尺寸偏差;
Mp3FrameRaw框架;
...
frame.fff=输入[offset++];
frame.fff=(frame.fff>4);
frame.mpeg_标准=(输入[offset]>>3)和1;
frame.layer=(输入[offset]>>1)&0x3;
frame.error_protection=(输入[offset++])&0x1;
frame.bitrate=输入[offset]>>4;
...
}
我假设位字段的位置不符合直觉。我做错了什么


我在Ubuntu18.04上使用gcc。

反问:那么你认为上面的
fff
字段映射到int32的12个最低有效位,还是12个最高有效位?这个条件
input[offset]&0xF0==0xF0
不应该是
input[offset]&0xFB==0xFB
?正如我从这个头结构示例中看到的,FFF后面的下一位是B P.S。我认为问题不在位字段中,而是在
重新解释后的字节顺序。我尝试了
uint32\u t*val=reinterpret\u cast(input.data()+offset)并获得了
04c8fbff
而不是预期的
fffb8c40
谢谢,@Gover Nator。事实证明,如果我颠倒结构中成员的顺序,一切都会正常进行。
reinterpret\u cast
使用这种方式具有未定义的行为,正确的做法是将
memcpy
转换为结构(通常会进行优化)或者使用C++20的
std::bit_cast
。反问:那么您是否假设上面的
fff
字段映射到int32的12个最低有效位,或者12个最高有效位?该条件
input[offset]&0xF0==0xF0
不应该是
input[offset]&0xFB==0xFB
?正如我从这个头结构示例中看到的,FFF后面的下一位是B P.S。我认为问题不在位字段中,而是在
重新解释后的字节顺序。我尝试了
uint32\u t*val=reinterpret\u cast(input.data()+offset)并获得了
04c8fbff
而不是预期的
fffb8c40
谢谢,@Gover Nator。事实证明,如果我颠倒结构中成员的顺序,一切都很好。
reinterpret\u cast
使用这种方式有未定义的行为,正确的做法是
memcpy
到结构中(通常会被优化掉)或使用C++20的
std::bit\u cast
3071 (Should always be 4095)
3 (Should be 1 )
0 (Should be 1 - 14)
{
    size_t offset;
    Mp3FrameRaw frame;        
    ...

    frame.fff = input[offset++];
    frame.fff = (frame.fff << 4) | (input[offset] >> 4);

    frame.mpeg_standard = (input[offset] >> 3) & 1;
    frame.layer = (input[offset] >> 1) & 0x3;
    frame.error_protection = (input[offset++]) & 0x1;
    frame.bitrate = input[offset] >> 4;
    ...

}