Delphi中声明ANSI字符串的大小

3

在旧的Delphi代码中,定义一个长度为3的字符串非常容易。

st:string[3];

现在,我们希望将代码移植到 ANSI。

st:ansiString[3];

无法工作!

对于高级OEM类型

st:oemString[3]; 

同样的问题,出现在哪里?
type
  OemString = Type AnsiString(CP_OEMCP);

如何声明一个固定长度的ANSI字符串和新的OEM类型?

更新:我知道这将创建一个固定长度的字符串。这是软件设计的一部分,旨在保护免受错误影响,并且对程序至关重要。


3
你为什么认为需要 AnsiString[3] - Cosmin Prund
1
那么你应该插入3个字符,不多不少。三应该是你插入字符的数量,而字符的数量应该是三个。除非你继续插入第三个字符,否则你不应该插入四个字符,也不应该插入两个字符。五是不行的。一旦插入了三个字符,达到了第三个数字,那么你就可以扔掉...,那些在我眼中淘气的人,将会被消灭。 - none
我认为Cosmin是指“Ansi”部分,而不是3。 - NGLN
@NGLN,有时候在生活中,其他公司不会推进技术,但你仍然希望他们为你的产品付款。因此,你需要继续使用他们旧的软件,并使用ANSI字符串与其进行接口交互。这不是我的选择。 - none
5个回答

5

您不需要定义 AnsiString 的大小。

表示法为

string[3] 

短字符串是Pascal(和Delphi 1)使用的简短字符串,主要为了保留遗留代码。

短字符串可以是1到255个字节长。第一个(“隐藏的”)字节包含长度。

AnsiString是指向字符缓冲区(以0结尾)的指针。它具有一些内部魔法,如引用计数。您可以安全地向现有字符串添加字符,因为编译器将处理所有令人讨厌的细节。

UnicodeStrings类似于AnsiStrings,但具有Unicode字符(在这种情况下为2个字节)。默认字符串现在(Delphi 2009)映射到UnicodeString。

类型AnsiString具有构造函数来添加代码页(用于定义127以上的字符),因此有CP_OEMCP:

OemString = Type AnsiString(CP_OEMCP);

1
如果您尝试使用固定长度的ansistring或unicodestring重新创建pchar,那么很可能会引入令人讨厌的缓冲区溢出问题,请不要这样做。让Delphi / c ++ builder处理字符串的长度。它会自动处理所有这些事情,在20年的编程经验中,我从未感觉需要覆盖该行为。 - Johan

4
“短字符串”是指“Ansi字符串”,因为它们仅用于向后兼容Delphi代码之前的版本。
       st: string[3];

自Delphi 2009以来,始终会使用当前的Ansi Code Page / Char Set创建固定长度的“短字符串”。
但是这样的短字符串与所谓的“AnsiString”不同。短字符串没有代码页。因为短字符串没有引用计数。
代码页仅适用于“AnsiString”类型,它们不是固定长度,而是可变长度且具有引用计数的完全不同类型,与由“string[...]”定义的短字符串不同。
按设计,您不能简单地混合使用“Short String”和“AnsiString”类型声明。两者都被称为“字符串”,但是它们是不同的类型。
以下是“Short String”的映射:
  st[0] = length(st)
  st[1] = 1st char (if any) in st
  st[2] = 2nd char (if any) in st
  st[3] = 3rd (if any) in st

这是 AnsiStringUnicodeString 类型的内存映射:

  st = nil   if st=''
  st = PAnsiChar if st<>''

这里是 PSt: PAnsiChar 的布局:

  PWord(PSt-12)^ = code page
  PWord(PSt-10)^ = reference count
  PInteger(PSt-8)^  = reference count
  PInteger(PSt-4)^  = length(st) in AnsiChar or UnicodeChar count
  PAnsiChar(PSt) / PWideChar(PSt) = Ansi or Unicode text stored in st, finished by a #0 char (AnsiChar or UnicodeChar)

因此,如果AnsiStringUnicodeString类型之间存在一些相似之处,那么short string类型则完全不同,并且不能像您希望的那样混合使用。


@user 对你来说,“null终止符不是必需的”是什么意思?即使你不需要它,它总是存在的。但是在调用Windows API时,例如使用简单的PChar(aString)表达式,它是必需的。 - Arnaud Bouchez
不是那么简单。它进行了类型转换,但发出了LStrToPChar调用,并且在那一点上可以插入#0。我对“总是”并不确定,有没有白皮书可以阅读? - Premature Optimization
1
@user 只需使用 pointer(aString),当 aString='' 时它将返回 nil,并且一个 PChar 指向 aString 的文本,没有 LStrToPChar / UStrToPChar。这就是为什么我在我的库中总是使用 pointer(aString) 来避免这个隐藏的调用。而且我对此非常确定,因为从 RTL 内部函数(我为了速度优化重写了一些部分,所以我对此有一定了解)。请看一下 System.pas 单元。 - Arnaud Bouchez
1
Delphi字符串确实是以空字符结尾的。可以通过将MyVar:= 'Hello',调用Setlength(MyVar,4)来轻松检查它。如果您检查MyVar,您会看到“o”已被#0替换(即使MyVar在原地重新分配)。 - Ken Bourassa
@Ken Bourassa,好的,我弄清楚了lstring管理的细节并删除了那个注释。 - Premature Optimization
@Downvoter 请查看此页面:http://docwiki.embarcadero.com/RADStudio/en/Internal_Data_Formats#Long_String_Types 或者“使用源代码,Luke” - 即 System.pas 单元。 - Arnaud Bouchez

2

只有当 Delphi 的 Unicode 版本中 String[3] 默认为 3 WideChars 时,这才有用。这让我感到惊讶,但如果确实如此,请使用以下代码:

st: array[1..3] of AnsiChar;

2
这里没有什么意外,String[3] 是在所有(已知的)Delphi Unicode 版本中使用的 Pascal 短字符串。将其更改为 WideChars 将会破坏许多特别使用它将字符串存储到固定大小记录中的代码。 - Cosmin Prund
这很愚蠢,如果你必须这样做,只需使用一个短字符串即可。 - Johan
@Cosmin Prund:听起来很合理。 - NGLN
感谢指出如何将string[3]转换为AnsiChar数组[1..3]。我本来会犯一个“差一”的错误。 - Sebastian

1

1
任何长度从0字符到2GB的内容;) - Arnaud Bouchez

1

但是与旧的ShortString类型不同,Delphi中的新字符串类型是动态的。它们会根据需要增长和缩小。您可以通过调用SetLength()来预分配给定长度的字符串,这对于避免重新分配内存非常有用,如果您必须逐个添加数据片段到一个您已知最终长度的字符串中,但即使在此之后,当添加或删除数据时,该字符串仍然可以增长和缩小。 如果您需要静态字符串,则可以使用char数组[0..n],其大小不会动态更改。


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