C++ 使用c+解包位字段+;产生错误的结果
我正在尝试使用位域解压mp3帧 mp3帧的标头以同步字0xFFF开头,后跟20位标头数据。标题的结构表示如下: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
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;
...
}