为什么记录的大小不等于其字段大小之和?

9

我有以下代码:

type TRecord1 = record
  myarr: array [0..31] of single:
end;
type TRecord2 = record
  b1, b2, b3, b4, b5, b6: byte;
end;
type TRecord3 = record
  myarr: array [0..31] of single:    
  b1, b2, b3, b4, b5, b6: byte;
end;

procedure TForm1.FormCreate(Sender: Tobject);
begin
  ShowMessage(IntToStr(SizeOf(TRecord1))+'+'+IntToStr(SizeOf(TRecord2))+
      '='+IntToStr(SizeOf(TRecord3)));
end;

该程序显示以下消息:
128+6=136

为什么 SizeOf(TRecord3) 的结果是 136 而不是 134?

经验之谈:如果您计划使用一些文件结构,请将它们声明为“packed”。 - OnTheFly
2
我的经验法则是永远不要将记录的二进制表示写入文件。 - David Heffernan
是的,应该避免存储二进制数据,但在进行I/O(dll's、串行通信等)时传递记录时,packed指令还是有用的。然而,在新开发中应使用标准化的二进制/字符串转换技术。 - LU RD
2个回答

15
这是由于记录对齐而添加的填充导致的。 TRecord3 具有对齐值为 4,因为它包含 single 值。因此,在记录的末尾添加了填充以使大小成为 4 的精确倍数。这就是为什么大小为 136 而不是您期望的 134 的值。
您可以声明要 packed 记录,或者等效地将对齐编译器选项设置为 $ALIGN 1。 对于 1 的对齐方式,不会向记录添加填充,SizeOf(TRecord3)=134。 但是,我强烈建议您不要这样做。使用自然对齐会导致记录的最有效的内存访问。例如,处理器加载未对齐的值比加载对齐的值更昂贵。对于 singleinteger,自然对齐在 4 字节边界上。对于 double,自然对齐在 8 字节边界上等等。如果需要与另一个使用打包记录的库实现二进制兼容性,则应使用打包记录。

2
此外,您可以将声明更改为 type TRecord3 = packed record ... 以防止记录对齐,尽管通常情况下您不需要这样做。对齐的记录性能更好,但在某些情况下,您可能需要紧凑的记录。 - GolezTrol

4

这是由于对齐引起的。记录中的字段按照4字节或8字节(或仅使用字节时为字节)对齐,以使得当记录在数组中时所有字段都保持对齐。如果您想让公式起作用,应使用“紧凑记录”。请注意,字段可能未对齐,可能会影响性能。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接