将Delphi 3迁移到Delphi 2010时遇到的字符串问题

5

我拿到了一个老项目的源代码,需要做一些小修改,但因为只有Delphi 2010,所以陷入了麻烦。

这里定义了一个记录:

bbil = record
  path : string;
  pos: byte;
  nr: Word;
end;

稍后这个定义将用于从文件中读取:
b_bil: file of bbil;
pbbil: ^bbil;
l_bil : tlist;

while not(eof(b_bil)) do
  begin
    new(pbbil);
    read(b_bil, pbbil^);
    l_bil.add(pbbil);
  end

主要问题是编译器不接受记录中的“string”类型,因为他想要一个“finalization”。 所以我尝试将“string”更改为“string[255]”或“shortstring”。这样做,应用程序读取文件但内容错误。 我的问题是如何将旧的“string”类型转换为Delphi 2010中的“新”类型。我已经尝试了很多方法,例如“{$H-}”。仅在记录中添加一个字符显示文件是正确的,因为读取的文件几乎是正确的,但每个数据集都被截断了一个字符 - 长度字节+255个字符的长度似乎对于定义是正确的,但shortstring不匹配。

在记录定义中使用 AnsiString 也会导致编译器错误:"需要 bbil 的完成"。以这种方式缩短 AnsiString "pfad:AnsiString [255];" 也不起作用:"预期';'但却发现'['"。我可能需要的是 ShortAnsiString? - rseffner
2
在我看来,你的代码不应该在Delphi 3中编译通过;尝试使用path : array[0..N] of AnsiChar;,其中N是一些常数,可能是255。 - kludg
2
按照David的说法,将字符串声明为“ShortString”。如果需要对记录进行对齐,请尝试使用紧凑记录指令。为了使此代码在D3中正常工作,必须使用{$H-}指令。 - LU RD
如果您使用AnsiString,那么read如何工作呢?另一方面,唯一真正有意义的解释是,ShortString 显然也失败了。 - David Heffernan
嗨Serg,我将提到的代码与2007年的备份进行了比较 - 记录定义和读取文件的过程与此处提到的完全相同。 - rseffner
哈哈,是的,抱歉,我在胡说八道。当然,通用的 AnsiStrings 也会失败。从 Delphi 1 开始迁移吧 :-) Turbo Pascal 字符串和可能是字(?)对齐的字段。 - OnTheFly
3个回答

5
哎呀!看起来您的代码要么是旧版的,要么不使用长字符串。如果您想获得与旧版Delphi相同的行为,则需要将string替换为ShortString
我看到您已经尝试过了,并报告说它失败了。这是唯一让我感到有道理的解释,因为所有其他字符串类型本质上都是指针,所以read能够起作用的唯一方法就是使用ShortString。您正在尝试的迁移非常庞大,可能会遇到许多混淆问题。
评论中@LU RD提出了一个很好的观点,即记录布局可能因为您未使用packed数组而在Delphi版本之间有所不同。您可以使用手头的两个Delphi版本来调查记录布局。您需要安排版本之间记录的大小相匹配,并且字段的偏移量也相匹配。
基于下面的评论,在pos和nr之间添加填充字节将解决您的问题。
bbil = record
  path : string;
  pos: byte;
  _pad: byte;
  nr: Word;
end;

你也可以通过将编译器选项 $ALIGN 设置为 {$ALIGN ON} 来实现相同的效果,这是我认为应该采取的方法。
从长远来看,你真的应该避免使用短字符串、ANSI 编码、内部记录和数据文件之间的直接映射等。从短期来看,你最好获取与构建此代码所使用的 Delphi 版本相同的版本,并使用该版本。我预计这个问题只是冰山一角。

David,我认为“ShortString”建议是正确的,只需要记录的大小匹配即可。对齐指令可以解决这个问题,或者也可以使用紧凑记录声明。 - LU RD
1
只需将类型声明为 packed record 而不是 record。这将消除编译器所做的对齐。要查看记录的大小,请尝试使用 SizeOf(bbil) - LU RD
1
请记住,自 Delphi 2009 版本以来,Char 变量占用两个字节。 - LU RD
1
然后在pos之后添加一个垃圾字节,这样你的代码就可以正常工作了。 - LU RD
1
由于编译器可以将字节值对齐到偶数地址,从而在下一个参数之间留出空间。甚至可以让编译器在四元地址上进行对齐。因此,在处理IO期间,请将记录声明为紧凑的。 - LU RD
显示剩余8条评论

2

请记住:

"string" <> "string[255]" <> "shortstring" <> AnsiString

在旧的DOS/Turbo Pascal时代,“字符串”确实被限制为255个字符。这在很大程度上是因为第一个字节包含了字符串长度,而一个字节只能有0到255的值。

在当代版本的Delphi中,这已经不再是问题。

"ShortString"是旧的DOS/Pascal字符串类型。

"LongString"长期以来一直是默认的字符串类型(包括我目前用于大部分生产工作的Borland Delphi 2006)。从Delphi 3 .. Delphi 2009,LongStrings包含8位字符,并且仅受可用内存限制。从Delphi 3 .. Delphi 2009,“LongStrings”是“AnsiStrings”的同义词。

最近版本的Delphi(包括新的Delphi XE2)都默认使用多字节Unicode“WideString”字符串。WideStrings和AnsiStrings一样,也可以有效地具有“无限”的最大长度。
本文将详细解释:

http://delphi.about.com/od/beginners/l/aa071800a.htm

PS:考虑使用“sizeof(bbil)”和“Packed”来处理二进制记录。

1
在Delphi术语中,长字符串既指AnsiString又指UnicodeString,后者是在D2009中引入的新字符串类型。而WideString又有所不同,它是COM BSTR的包装器。 - David Heffernan
2
@rseffner - 术语可能会让人感到困惑。这主要是微软的错。请查看我引用的链接(特别是“about.com”文章),以了解字符串。请尝试使用“sizeof()”来排除二进制记录的打包和对齐问题。 - paulsm4
1
术语非常清晰,与微软无关。所涉及的语言是由Embarcadero生产的。我之前的评论是试图引导您修复答案中的各种错误。目前来看,它相当不准确。 - David Heffernan
在某些Delphi版本中,String = AnsiString。例如,所以保罗,大卫指出你在回答中发表了不正确的陈述。实际上,在所有版本的Delphi中,“String”不是一种类型,而是另一种类型的别名,可以是Delphi 1中的“ShortString”,Delphi 2到2007年的“AnsiString”和2009年至今的“UnicodeString”。因此,这比您的一系列不等式更清晰,而这些不等式并不严格正确。我不相信LongString是一个类型名称、别名或文档术语。 - Warren P

0
也许我忽略了什么,但是在我看来,你的Delphi 3代码也有问题。尝试确定记录的大小:
bbil = record
  path : string;
  pos: byte;
  nr: Word;
end;

路径(长度在1到256之间 - 一个字节表示长度,其余为数据),位置(1个字节),序号(2个字节),使您的记录数据大小从1 + 1 + 2 = 4个字节到256 + 1 + 2 = 259个字节不等。在这种情况下,您无论如何都会从文件中获取垃圾数据,因为您的程序不知道在实际读取数据之前要读取多少字节。我建议您调整记录大小,使其成为固定大小的字符串,例如:

path : ShortString[255];

那么,您将能够在Delphi 3和2010中编写和读取良好的内容。


再说,Delphi 3没有shortstring类型,你必须在Delphi 3中将其定义为字符串。 - Tuncay Göncüoğlu

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