我正在尝试在小端机上使用FreePascal来读取和解释集成电路中的数据。数据本质上是由紧密打包(主要是)的大端整数组成,其中一些(实际上很多)未对齐字节边界。因此,我为此尝试使用FPC的bitpacked
记录,发现自己陷入了深深的麻烦之中。
我尝试读取的第一个结构具有以下格式:
{$BITPACKING ON}
type
THeader = bitpacked record
Magic: Byte; // format id, 8 bits
_Type: $000..$FFF; // type specifier, 12 bits
Version: Word; // data revision, 16 bits
Flags: $0..$F // attributes, 4 bits
end;
这是一个阅读代码:
procedure TForm1.FormCreate(Sender: TObject);
var
F: File;
Header: THeader;
begin
Writeln(SizeOf(Header), #9, BitSizeOf(Header)); // reports correctly
Writeln('SizeOf(Header._Type) = ', SizeOf(Header._Type)); // correctly reports 2 bytes
Writeln('BitSizeOf(Header._Type) = ', BitSizeOf(Header._Type)); // correctly reports 12 bits
AssignFile(F, 'D:\3fd8.dat');
FileMode := fmOpenRead;
Reset(F, SizeOf(Byte));
BlockRead(F, Header, SizeOf(Header));
{ data is incorrect beyond this point already }
//Header._Type := BEtoN(Header._Type);
Writeln(IntToHex(Header.Magic, SizeOf(Header.Magic) * 2));
Writeln(IntToHex(BEtoN(Header._Type), SizeOf(Header._Type) * 2));
Writeln(BEtoN(Header.Version));
end;
但是代码正在打印完全错误的数据。
这是手动完成的数据和解释:
0000000000: F1 55 BE 3F 0A ...
Magic = F1
_Type = 55B
Version = E3F0
Flags = A
但是FPC以严重不同和错误的方式查看数据。似乎由于主机的字节序少,属于字段的半字节(和位)不连续(例如:半字节
B
通常应属于_Type
字段,而半字节E
-属于Version
)。这是拉撒路的手表窗口:请告知我该怎么做。这个非连续的位域是FPC的错误吗?有任何解决方法?
最佳答案
字节数
F1 55 BE 3F 0A
具有以下连续的半字节(高半字节之前是低半字节):
1 F 5 5 E B F 3 A 0
如果将它们分别分为2、3、4和1个半字节,则得到:
1 F --> $F1
5 5 E --> $E55 // highest nibble last, so E is highest.
B F 3 A --> $A3FB // same again: A is highest nibble
0 --> $0
这对应于您在“监视”窗口中看到的结果,而不是您手动解码的结果。
现在,如果数据是big-endian格式,则必须使用移位和掩码手动解码:
X.Magic := bytes[0];
X._Type := (bytes[1] shl 4) or (bytes[2] shr 4);
X.Version := ((bytes[2] and $0F) shl 12) or
(bytes[3] shl 4) or
(bytes[4] shr 4);
X.Flags := bytes[4] and $0F;
关于delphi - Little-endian机器问题上的“bitpacked”记录,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31848246/