end*_*nge 8 delphi delphi-7 endianness
我很困扰。我需要读取二进制文件(Applied Biotechnology aka ABIF 的 .fsa 扩展名、FASTA 文件),但在读取有符号整数时遇到了问题。我正在根据本手册做所有事情https://drive.google.com/file/d/1zL-r6eoTzFIeYDwH5L8nux2lIlsRx3CK/view?usp=sharing 所以,例如,让我们看看文件https头中的 fDataSize 字段: //drive.google.com/file/d/1rrL01B_gzgBw28knvFit6hUIA5jcCDry/view?usp=sharing
我知道它应该是 2688(根据手册,它是一个 32 位的有符号整数),即二进制形式的 00000000 00000000 00001010 10000000。实际上,当我将这 32 位读取为 4 个字节的数组时,我得到 [0, 0, 10, -128],这与二进制形式完全相同。
但是,如果我将其读为整数,则会得到 16809994,即 00000001 00000000 10000000 00001010 位。
正如我从多个论坛了解到的,他们使用 Swap 和 htonl 函数将整数从小端顺序转换为大端顺序。他们还建议对 32 位整数使用 BSWAP EAX 指令。但在这种情况下,它们以一种错误的方式工作,特别是:Swap,应用于 16809994,返回 16779904 或 00000001 00000000 00001010 10000000,并且 BSWAP 指令将 16809996, 01001001001001001001001001001001001001001001001001001001001
正如我们所看到的,内置函数的作用与我需要的不同。Swap 可能会返回正确的结果,但是由于某种原因,将这些位作为整数读取会更改最左侧的字节。那么,出了什么问题,我该怎么办?
更新。1 为了存储标题数据,我使用以下记录:
type
TFasMainHeader = record
fFrmt : array[1..4] of ansiChar;
fVersion : Word;
fDir : array[1..4] of ansiChar;
fNumber : array[1..4] of Byte; //
fElType : Word;
fElSize : Word;
fNumEls : array[1..4] of Byte; //
fDataSize : Integer;
fDataOffset : Integer;
fDO : word;
fDataHandle : array[1..98] of Byte;
end;
Run Code Online (Sandbox Code Playgroud)
然后单击按钮后,我执行以下操作:
aFileStream.Read(fas_main_header, SizeOf(TFasMainHeader));
with fas_main_header do begin
if fFrmt <> 'ABIF' then raise Exception.Create('Not an ABIF file!');
fVersion := Swap(fVersion);
fElType := Swap(fElType);
fElSize := Swap(fElSize);
...
Run Code Online (Sandbox Code Playgroud)
接下来我需要以正确的方式交换Int32变量,但此时fDataSize例如为16809994。 调试时详细查看记录的状态:
这对我来说没有意义,因为 fDataSize 值的二进制表示中不应该有一位(它也会破坏 BSWAP 结果)。
And*_*and 11
问题与字节顺序无关,而是与 Delphi记录有关。
你有
type
TFasMainHeader = record
fFrmt : array[1..4] of ansiChar;
fVersion : Word;
fDir : array[1..4] of ansiChar;
fNumber : array[1..4] of Byte; //
fElType : Word;
fElSize : Word;
fNumEls : array[1..4] of Byte; //
fDataSize : Integer;
fDataOffset : Integer;
fDO : word;
fDataHandle : array[1..98] of Byte;
end;
Run Code Online (Sandbox Code Playgroud)
并且您希望此记录覆盖文件中的字节,并带有fDataSize"on top of" 00 00 0A 80。
但是 Delphi 编译器会在记录的字段之间添加填充以使它们正确对齐。因此,您fDataSize将不会处于正确的偏移量。
要解决此问题,请使用packed关键字:
type
TFasMainHeader = packed record
fFrmt : array[1..4] of ansiChar;
fVersion : Word;
fDir : array[1..4] of ansiChar;
fNumber : array[1..4] of Byte; //
fElType : Word;
fElSize : Word;
fNumEls : array[1..4] of Byte; //
fDataSize : Integer;
fDataOffset : Integer;
fDO : word;
fDataHandle : array[1..98] of Byte;
end;
Run Code Online (Sandbox Code Playgroud)
然后字段将位于预期位置。
然后——当然——你可以使用任何你喜欢的方法来交换字节顺序。
最好是BSWAP指令。