2012-03-21 35 views
8

我有下一个代码:为什么记录的大小不等于其字段大小的总和?

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?

+0

经验法则:如果您打算在文件中使用某些结构 - 将它们声明为“packed”。 – OnTheFly 2012-03-21 15:03:22

+2

我的经验法则是永远不会将记录的二进制表示写入文件 – 2012-03-21 17:21:13

+0

是避免存储二进制数据,但打包的指令在I/O(dll's,串行通信等)期间传递记录时使用它。尽管使用标准化的二进制/字符串转换技术应该适用于新的开发。 – 2012-03-21 18:11:08

回答

15

这是由于记录对齐而添加的填充。由于它包含single值,因此TRecord3的对齐方式为4。因此,填充将添加到记录的末尾,以使大小成为4的整数倍。这就是为什么大小是136而不是您期望的值134。

您可以声明您的记录为packed,或者等价地将对齐编译器选项设置为$ALIGN 1。如果对齐为1,则不会在记录中添加填充和SizeOf(TRecord3)=134。不过,我强烈建议你不要这样做。使用自然对齐会为记录提供最有效的内存访问。例如,处理器加载未对齐的值比加载对齐的值要昂贵。对于singleinteger,自然对齐位于4字节的边界上。对于double,自然对齐位于8字节的边界上,依此类推。如果您需要与使用打包记录的另一个库进行二进制兼容,则应使用打包记录。

+2

此外,您可以将声明更改为'输入TRecord3 = packed record ...'以防止记录对齐,尽管通常您不需要。对齐的记录效果更好,但在某些情况下,您可能需要打包的记录。 – GolezTrol 2012-03-21 11:04:58

4

这是由于对齐。记录中的字段在4个字节或8个字节(或只有在记录中使用字节时的字节)上对齐,以便在数组中所有字段的记录将保持对齐。如果你想要公式起作用,你应该使用'打包记录'。请注意,这些字段可能未对齐,可能会影响性能。

相关问题