Jas*_*ott 8 delphi record delphi-2009 delphi-2010
将代码从Delphi 7转换到2010时,我遇到了一个奇怪的问题.它与记录有关.下面定义的记录,在D7中的大小为432字节,在D2009(和2010年)中为496.我知道,一个简单的解决方案是使其成为打包记录,然后所有版本都达到426字节......但是,我们将数据存储在我们流式传输记录的位置,现在我们正在尝试使用更新的语言读取这些流.
TToTry = Record
a,b,c,d : Extended;
e,f,g,h : Extended;
i : String[15];
j,k,l,m,n,o,p,q,r,s,t : Array[1..3] of Extended; End;
Run Code Online (Sandbox Code Playgroud)
在调查这个问题时,我创建了另一条记录,无论出于何种原因,大小都相同?记录较小,但它具有相同的数据类型.但它在所有版本的语言中都有相同的大小.
TMyRecord = Record
Ext1 : Extended;
Ext2 : Extended;
Ext3 : Extended;
Ext4 : Extended;
Ext5 : Extended;
Ext6 : Extended;
Int1 : Integer;
Int2 : Integer;
char1 : AnsiChar;
char2 : AnsiChar;
MyString : String[15];
Arr1 : Array[1..3] of Extended;
Arr2 : Array[1..3] of Extended; end;
Run Code Online (Sandbox Code Playgroud)
任何人都知道为什么一个记录如此不同,另一个是相同的?与Delphi中的字节边界对齐有关.但是从一个版本到下一个版本的变化如此之大?
dth*_*rpe 14
那么,第一个问题是您将非打包记录存储到磁盘.允许字段和数组打包在产品版本之间进行更改,因为通常内存中的布局在进程外部不可见.你违反了这个规则.
如果Delphi 7和Delphi 2009之间的字节填充默认值发生了变化,请找出D7中的默认值,并在Delphi 2009中将默认值设置为相同.
还要检查阵列打包默认值.我不记得是否有单独的设置.
在调试内存视图中查看Delphi 2009中的记录结构.部分或全部附加大小可能是由于记录本身的填充(不是其中的字段),因此当在阵列中使用记录时,阵列元素处于快速的机器边界上.
如果这些都没有帮助,请在D2009中创建临时打包记录类型,并在实际数据字段之间手动插入字节填充字段,直到记录大小和字段对齐与D7布局匹配.它不仅仅是尺寸,而是场对齐.使用此临时打包记录读取旧数据文件.然后将数据字段按字段传输到D2009中的"实际"记录类型并写出新文件.
当你在它的时候,在D2009中打包记录类型,这样就不会再发生了.
我相信你已经打了一个功能!你TToTry用D2007 得不到合理的尺寸,所以我不得不用调试器查找字段地址;
首先,以下记录的大小,
{$A8}
type
TToTry = record
j: array[1..3] of Extended;
k: array[1..3] of Extended;
l: array[1..3] of Extended;
m: array[1..3] of Extended;
end;
Run Code Online (Sandbox Code Playgroud)
是128(32*4).这是预期的,因为a Extended是10个字节,30个字节将在32个字节上对齐.
但是这个记录的大小,
{$A8}
type
TToTry = record
j, k, l, m: array[1..3] of Extended;
end;
Run Code Online (Sandbox Code Playgroud)
是120(30*4).这当然是意料之外的 - 字段仍然应该在8字节边界上对齐.
(我没有D7来验证,但我的想法是:)
所以现在我们知道分组字段是打包的,因此D7上的对齐是8个字节,你的记录几乎是打包的;
TToTry = Record
a,b,c,d : Extended; // 40 bytes (8*5)
e,f,g,h : Extended; // 40 bytes (8*5)
i : String[15]; // 16 bytes (8*2)
j,k,l,m,n,o,p,q,r,s,t: Array[1..3] of Extended; // 330 bytes
End;
Run Code Online (Sandbox Code Playgroud)
编译器将6个字节填充到最后一个组,使其为8的倍数,然后得到40 + 40 + 16 + 336 = 432个字节.
使用D2009/D2010,您要么声明每个字段 - 不对它们进行分组,要么更改行为.无论哪种方式打包你的记录并添加一个6字节的数组虚拟字段到最后,你应该很高兴去.
如果这不起作用,请使用D7查看记录的字段地址,然后在D2009上使用打包记录并根据需要使用虚拟字段创建完全相同的副本,在导入存储的数据后,您可以删除虚拟字段.
-
我从来不知道这种行为,我无法在任何地方找到它.不过,它非常像一个功能,我犹豫不决称它为一个bug.我不知道D2009或D2010的行为是否相同,测试是否是.如果是,为了得到预期的结果 - 不要有半打包记录 - 不要懒惰并且为非打包记录声明每个字段.
我相信默认对齐方式变宽了。在以后的版本中指定对齐方式 4,看看它是否按照您想要的方式显示。
将来,您应该确保任何要写入磁盘的记录都以打包方式存储,这样您就不会被这种方式烧毁。
编辑:由于没有任何对齐方式起作用(这让我感到惊讶),我会回到原始版本并弄清楚它是如何真正对齐的。用类似 $FF 的内容填充记录,将数据放入并写出 - 查看 $FF 幸存的位置。获取新记录,对其进行打包并添加填充符以匹配旧记录中的填充。
一件事:这实际上只是一张记录吗?过去,我使用对象作为带有继承的假记录——哎呀,在继承时应用了正常对齐,我无法阻止它。我最终不得不在数据之前进行填充,以使强制对齐不会破坏我的数据。(这是一个 API,它必须是正确的,我无法独立处理这些字段。)
| 归档时间: |
|
| 查看次数: |
1785 次 |
| 最近记录: |