delphi中的字符串的问题,头都大了。(100分)

  • 主题发起人 主题发起人 wolf83422
  • 开始时间 开始时间
W

wolf83422

Unregistered / Unconfirmed
GUEST, unregistred user!
哪位替在下把delphi中的字符串理理清
(ansisting,widesting,pchar....)
谢谢!
 
2.6.2 字符
D e l p h i有三种类型的字符:
•
AnsiChar 这是标准的1字节的A N S I字符,程序员都对它比较熟悉。
•
WideChar 这是2字节的U n i c o d e字符。
•
Char 在目前相当于A n s i C h a r, 但在D e l p h i以后版本中相当于Wi d e C h a r.
记住因为一个字符在长度上并不表示一个字节,所以不能在应用程序中对字符长度进行硬编码,
而应该使用S i z e o f ( )函数。
注意Sizeof()标准函数返回类型或实例的字节长度。
2.6.3 字符串
字符串是代表一组字符的变量类型,每一种语言都有自己的字符串类型的存储和使用方法。
P a s c a l类型有下列几种不同的字符串类型来满足程序的要求:
•
AnsiString 这是P a s c a l缺省的字符串类型,它由AnsiChar 字符组成,其长度没有限制,同时与
n u l l结束的字符串相兼容。
•
ShortString 保留该类型是为了向后兼容Delphi 1.0,它的长度限制在2 5 5个字符内。
•
WideString 功能上类似于A n s i S t r i n g,但它是由Wi d e C h a r字符组成的。
•
PChar 指向n u l l结束的C h a r字符串的指针,类似于C的char * 或l p s t r类型。
•
PAnsiChar 指向n u l l结束的A n s i C h a r字符串的指针。
•
PWideChar 指向n u l l结束的Wi d e C h a r字符串的指针。
缺省情况下,如果用如下的代码来定义字符串,编译器认为是AnsiString 字符串:
v a r
S:string;
//编译器认为S的类型是A n s i S t r i n g
当然,能用编译开关$ H来将s t r i n g类型定义为S h o r t S t r i n g,当$ H编译开关的值为负时, s t r i n g变量
是S h o r t S t r i n g类型;当$ H编译开关的值为正时(缺省情况),字符串变量是A n s i S t r i n g类型。下面的代码
演示了这种情况:
v a r
{ $ H - }
S1:string;
//S1是S h o r t S t r i n g类型
{ $ H + }
S2:string;
//S2是A n s i S t r i n g类型
使用$ H规则的一个例外是,如果在定义时特地指定了长度(最大在2 5 5个字符内),那么总是
S h o r t S t r i n g:
v a r
S: string[63];
//63个字符的S h o r t S t r i n g字符串
1. AnsiString类型
A n s i S t r i n g (或长字符串)类型是在Delphi 2.0开始引入的,因为Delphi 1.0的用户特别需要一个容易
使用而且没有2 5 5个字符限制的字符串类型,而A n s i S t r i n g正好能满足这些要求。
2 4 第一部分快速开发的基础
下载
第2章Object Pascal语言2 5
虽然A n s i S t r i n g在外表上跟以前的字符串类型几乎相同,但它是动态分配的并有自动回收功能,正
是因为这个功能A n s i S t r i n g有时被称为生存期自管理类型。Object Pascal能根据需要为字符串分配空间,
所以不用像在C / C + +中所担心的为中间结果分配缓冲区。另外, A n s i S t r i n g字符串总是以n u l l字符结束
的,这使得A n s i S t r i n g字符串能与Win32 API 中的字符串兼容。实际上,A n s i S t r i n g类型是一个指向在堆
栈中的字符串结构的指针。
警告Borland没有将长字符串类型的内部结构写到文档中,并保留了在Delphi后续版本中修改
长字符串内部格式的权利。在这里介绍的情况主要是帮助你理解A n s i S t r i n g类型是怎样工作的
并且在程序中要避免直接依赖于AnisString结构的代码。
程序员如果在Delphi 1.0中避免了使用字符串的内部结构,则把代码移植到Delphi 2.0没有
任何问题。而依赖于字符串内部结构写代码的程序在移植到Delphi 2.0时必须修改。
正如图2 - 1演示的,A n s i S t r i n g字符串类型有引用计数的功能,这表示几个字符串都能指向相同的
物理地址。因此,复制字符串因为仅仅是复制了指针而不是复制实际的字符串而变得非常快。
图2-1 显示了AnsiString在内存中分配的情况
当两个或更多的A n s i S t r i n g类型共享一个指向相同物理地址的引用时, D e l p h i内存管理使用了
c o p y - o n - w r i t e技术,一个字符串要等到修改结束,才释放一个引用并分配一个物理字符串。下面的例
子显示了这些概念:
v a r
S 1 , S 2 : s t r i n g ;
b e g i n
/ /给S 1赋值,S 1的引用计数为1
S1:='And now for something...';
S2:=S1;
//现在S 2与S 1指向同一个字符串, S 1的引用计数为2
/ / S 2现在改变了,所以它被复制到自己的物理空间,并且S 1的引用计数减1
S2:=S2+'completely diff e r e n t 1 ' ;
e n d ;
生存期自管理类型
除了A n s i S t r i n g以外, D e l p h i还提供了其他几种生存期自管理类型,这些类型包括:
Wi d e S t r i n g、Va r i a n t、O l e Va r i a n t、i n t e r f a c e、d i s p i n t e r f a c e和动态数组,这些类型在本章稍后有
介绍,现在,我们重点讨论究竟什么是生存期自管理,以及它们是如何工作的。
生存期自管理类型,又被称为自动回收类型,是指那些在被使用时就占用一定的特殊资
源,而在它离开作用域时自动释放资源的类型。当然不同的类型使用不同的资源,例如,
A n s i S t r i n g类型在被使用时就为字符串占用内存,当它超出作用域时就释放被字符串占用的内
存。
对于全局变量,这种情况是相当直观的:作为应用程序结束代码的一部分,编译器自动
插入代码来清除每一个生存期自管理类型的全局变量。因为在应用程序在被装入时,全局变量
都被初始化为0,每一个全局变量将用初始化时的0、空或其他值来指示它还没有被使用,基于
这种方法,终止代码只清除那些确实在应用程序中被使用的全局变量。
对于局部变量来讲,这种情况稍微有的复杂:首先,在过程或函数开始运行时,编译器
插入的代码保证初始化这些局部变量,接着,编译器产生一个t r y. . . f i n a l l y的异常处理块,它包
分配的大小引用计数长度
下载
容整个函数体,最后,编译器在f i n a l l y块插入代码来清除生存期自管理变量(异常处理块在2 . 1 9
节“结构化异常处理”中介绍),为了能记住这些,请看下面的代码:
procedure Foo;
v a r
S : s t r i n g ;
b e g i n
/ /过程体
/ /在这里用S
e n d ;
虽然这个过程看起来简单,如果考虑进由编译器插入的代码,它看起来像下面的代码:
procedure Foo;
v a r
S : s t r i n g ;
b e g i n
S:=' ';
t r y
/ /过程体
/ /在这里用S
f i n a l l y
/ /在这里清除S
e n d ;
e n d ;
(1) 字符串运算符
能用+运算符或C o n c a t ( )函数来连接两个字符串,推荐使用+运算符,因为C o n c a t ( )函数主要用来向
后兼容,下面代码演示了+运算符和C o n c a t ( )函数的用法:
注意在Object Pascal中,通常用一对单引号来把字符串括起来,例如'A String'。
提示C o n c a t ( )是众多“编译器魔术”过程和函数中的一个,其他还有R e a d L n ( )、Wr i t e L n ( ) .、
它们没有Object Pascal的定义。这些函数接收不确定个数的参数或可选的参数,它们不能根据
Object Pascal语言来定义,正因为这样,编译器为每一个这样的函数提供了特殊的条件,并产
生一个对堆栈函数的调用,这些堆栈函数定义在S y s t e m单元中,它们为了越过P a s c a l的语言规
则,通常是用汇编语言实现的。
2 6 第一部分快速开发的基础
下载
{用+运算符}
{ 用Concat() }
除了“编译器魔术”字符串函数和过程外,在S y s U t i l单元中有许多函数和过程用来使字
符串更易使用,请查阅Delphi的联机帮助“字符串处理例程”。
此外,可以在本书附带的C D - R O M的/ S o u r c e / U t i l s目录中的S t r U t i l s单元中找到更多用来处
理字符串的过程和函数。
(2) 长度和分配
第一次声明A n s i S t r i n g时,它是没有长度的,因此在字符串中就没有为字符分配空间。为了对字符
串分配空间,用一行字母或另一个字符串对它进行赋值,或者用S e t L e n g t h ( )过程,就像下面所列出来
的:
v a r
S:string ;
// 字符初始化时,没有长度
b e g i n
S : = ' D o h ! ' ;
/ /为字符串的字母分配足够的空间
{或者}
S : = O t h e r S t r i n g ;
/ /增加O t h e r S t r i n g的引用计数,
/ / {假定O t h e r S t r i n g指向一个合法的字符串}
{或者}
S e t L e n g t h ( S , 4 ) ;
/ /分配4个字符的空间
e n d ;
能像数组一样对字符串进行索引,但注意索引不要超出字符串的长度,例如,下面的代码会引起
一个错误:
v a r
S : s t r i n g ;
b e g i n
S[1]:='a';
//不能工作,因为S没有被分配空间
e n d ;
然而,代码改成如下,就能正常工作了:
v a r
S : s t r i n g ;
b e g i n
S e t L e n g t h ( S , 1 ) ;
S[1]:='a';
//现在S有足够空间来容纳字符
e n d ;
(3) Wi n 3 2的兼容
正如前面所提到,A n s i S t r i n g字符串总是null 结束的。因此,它能跟以n u l l结尾的字符串兼容,这
就使得调用Win32 API 函数或其他需要P C h a r型字符串的函数变得容易了。只要把一个字符类型强制转
换为P C h a r类型(在2 . 8节“强制类型转换和类型约定”中将介绍强制类型转换)。下面的代码演示了怎
样调用Wi n 3 2的G e t Wi n d o w s D i r e c t o r y ( )函数,这个函数需要一个P C h a r类型的参数:
v a r
S : S t r i n g ;
b e g i n
SetLength(S,256);
//重要!首先给字符串分配空间
/ /调用A P I函数,S 现在包含目录字符串
G e t Wi n d o w s D i r e c t o r y ( P C h a r ( S ) , 2 5 6 ) ;
如果使用了将A n s i S t r i n g字符串强制转换为P C h a r类型的函数和过程,在使用结束后,要手工把它
第2章Object Pascal语言2 7 下载
的长度恢复为原来以n u l l结束的长度。S T R U T I L S单元中的R e a l i z e L e n g h t ( )函数可以实现这一点:
procedure RealizeLength(var S:string);
b e g i n
S e t L e n g t h ( S , S t r L e n ( P C h a r ( S ) ) ) ;
e n d ;
调用R e a l l i z e L e n g t h ( ) :
v a r
S : s t r i n g ;
b e g i n
SetLength(S,256);
//重要!首先给字符串分配空间
/ /调用函数,S现在包含目录字符串
G e t Wi n d o w D i r e c t o r y ( P C h a r ( S ) , 2 5 6 ) ;
RealizeLength(S);
//设置S的长度为n u l l结束的长度
e n d ;
注意在练习将一个字符串转换为P C h a r类型时要小心,因为字符串在超出其作用范围时有自
动回收的功能,因此当进行P:=PChar(Str)的赋值时,P的作用域(生存期)应当大于Str的作用域。
(4) 移植性问题
当要移植Delphi 1.0 的应用程序时,一定要注意几个关于A n s i S t r i n g的问题:
•
在使用P S t r i n g (指向S h o r t S t r i n g字符串的指针)的地方,应当替换成s t r i n g类型。记住:A n s i S t r i n g
已经是一个指向字符串的指针。
•
不能再通过字符串的第0个元素来设置或得到字符串的长度,只能通过L e n g t h ( )函数来得到字符
串的长度,通过S e t L e n g t h ( )过程来设置字符串的长度。
•
不再需要通过调用S t r P a s ( )和S t r P C o p y ( )来进行字符串与P C h a r之间的转换,正如上面所提到的,
可以把AnsiString 强制类型转换为P C h a r。如果要把P C h a r的内容复制到A n s i S t r i n g,直接用赋值
语句:
S t r i n g Var: =PCharVa r ;
警告对长字符串设置长度时,必须用SetLength()过程,过去那种通过直接访问字符串第0个元
素来设置长度的方法,在应用程序从16位的Delphi 1.0升级到32位时会出现问题。
2. ShortString类型
如果你是一个D e l p h i的老手,应该知道S h o r t S t r i n g类型是Delphi 1.0中字符串的类型, S h o r t S t r i n g
类型有时又被称为Psacal 字符串(Psacal string)或长度-字节字符串(length-byte string)。请记住,$H 编
译开关的值用来决定当变量声明为字符串时,它是被当作A n s i S t r i n g类型还是被当作S h o r t S t r i n g类型。
在内存中,字符串就像是一个字符数组,在字符串的第0个元素中存放了字符串的长度,紧跟在
后的字符就是字符串本身。S h o r t S t r i n g缺省的最大长度为2 5 6个字节,这表示在S h o r t S t r i n g中不能有大
于2 5 5个字符( 2 5 5个字符+ 1个长度字节= 2 5 6 )。相对于A n s i S t r i n g来说,用S h o r t S t r i n g
是相当随意的,因为编译器会根据需要为它分配空间,所以不用担心中间结果是不是
要预先分配内存。图2 - 2演示了P a s c a l字符串在内存中的分配方式。
一个S h o r t S t r i n g变量用下面的代码声明和初始化:
2 8 第一部分快速开发的基础
下载
图2-2
当然,能用s h o r t类型限定符和一个长度限制来为S h o r t S t r i n g分配小于2 5 6个字节的空间,示例如
下:
如上代码,这个字符串肯定是S h o r t S t r i n g,而不再受$ H编译开关的影响,能指定的短字符串的最
大长度是2 5 5个字符。
不要存放比分配给字符串的空间长度更长的字符,如果声明了一个变量是s t r i n g [ 8 ],并试图对这
个变量赋值为‘a _ p r e t t y _ d a r n _ l o n g _ s t r i n g’,这个字符串将被截取为仅有8个字符,就要丢失数据。
当用数组的下标来访问S h o r t S t r i n g中的一个特定字符时,如果下标的索引值大于声明时S h o r t S t r i n g
的长度,则会得到假的结果或造成内存混乱。例如,假定像下面那样声明了一个变量:
v a r
S t r : s t r i n g [ 8 ] ;
如果试图写这个字符串的第1 0个元素,则有可能使其他变量的内存混乱。
v a r
S t r : s t r i n g [ 8 ] ;
i : I n t e g e r ;
b e g i n
i : = 1 0 ;
Str:='s';
//内存混乱
可以在Project Options 对话框中选中Range Checking复选框,这样编译器会自动加上特殊的逻辑在
运行时捕捉此类错误。
提示虽然在程序中包括范围检查能发现字符串错误,但范围检查多少都影响应用程序的性能。
通常使用的方法是在开发程序或调试程序的阶段用范围检查,而在确信程序稳定时,去掉范围
检查。
跟A n s i S t r i n g类型字符串不一样, S h o r t S t r i n g跟以n u l l结尾的字符串不兼容,正因为这样,用
S h o r t S t r i n g调用Wi n 3 2函数时,要做一些工作。下面这个S h o r t S t r i n g A s P C h a r ( )函数是在S T R U T I L S . PA S
单元中定义的。
func function ShortStringAsPChar(var S:ShortString):PChar;
{这函数能使一个字符串以n u l l结尾,这样就能传递给需要P C h a r类型参数的Win32 API函数,如果字符串超过
2 5 4个字符,多出的部分将被截掉}
b e g i n
if Length(S)=High(S) then
Dec(S[0]);
{ 如果S 太长,就截取一部分}
S[Ord(Length(S))+1]:=#0;
{ 把n u l l加到字符串的最后}
Result:=@S[1];
{ 返回P C h a r化的字符串}
e n d ;
警告Win32 API函数需要以n u l l结尾的字符串,不要把S h o r t S t r i n g字符串传递给A P I函数,因
为编译器将报错,长字符串可以传递给Win32 API函数。
2. Wi d e S t r i n g类型
Wi d e S t r i n g类型像A n s i S t r i n g一样是生存期自管理类型,它们都能动态分配、自动回收并且彼此能
相互兼容,不过Wi d e S t r i n g和A n s i S t r i n g的不同主要在三个方面:
第2章Object Pascal语言2 9 下载
一个4 5个字符的S h o r t S t r i n g字符串
•
Wi d e S t r i n g由Wi d e C h a r字符组成,而不是由A n s i C h a r字符组成的,它们跟U n i c o d e字符串兼容。
•
Wi d e S t r i n g用S y s A l l o c S t r L e n ( ) A P I函数进行分配,它们跟O L E的B S T R字符串相兼容。
•
Wi d e S t r i n g没有引用计数,所以将一个Wi d e S t r i n g字符串赋值给另一个Wi d e S t r i n g字符串时,就
需要从内存中的一个位置复制到另一个位置。这使得Wi d e S t r i n g在速度和内存的利用上不如
A n s i S t r i n g有效。
就像上面所提到的,编译器自动在A n s i S t r i n g类型和Wi d e S t r i n g类型的变量间进行转换。示例如
下:
v a r
W: w i d e S t r i n g ;
S : s t r i n g ;
b e g i n
W: = ' M a r g a r i t a v i l l e ' ;
S : = W;
// wideString转换成A n s i S t r i n g
S:='Come Monday';
W:=S;
// AnsiString转换成Wi d e S t r i n g
e n d ;
为了能灵活地运用Wi d e S t r i n g类型, Object Pascal重载了C o n c a t ( )、C o p y、I n s e r t ( )、L e n g t h ( )、
P o s ( )和S e t L e n g t h ( )等例程以及+、=和< >等运算符。下面的代码在语法上是正确的:
v a r
W 1 , W 2 : Wi d e s t r i n g ;
P : I n t e g e r ;
b e g i n
W 1 : = ' E n f i e l d ' ;
W 2 : = ' f i e l d ' ;
If W1<>W2 then
P : = P o s ( W 1 , W 2 ) ;
e n d ;
就像A n s i S t r i n g和S h o r t S t r i n g类型一样,能用数组的下标来访问Wi d e S t r i n g中一个特定的字符:
v a r
W: Wi d e S t r i n g ;
C : Wi d e C h a r ;
b e g i n
W:='Ebony and Ivory living in prefect harmony';
C:=W[Length(W)];
//C包含W字符串的最后一个字符
e n d ;
4. 以n u l l结束的字符串
正如前面所提到的, D e l p h i有三种不同的以n u l l结束的字符串类型: P C h a r、PA n s i C h a r和
P Wi d e C h a r。它们都是由D e l p h i的三种不同字符组成的。这三种类型在总体上跟P C h a r是一致的。
P C h a r之所以保留是为了跟Delphi 1.0和Win32 API兼容,而它们需要使用以n u l l结束的字符串,P C h a r
被定义成一个指向以n u l l (零)结束的字符串指针(如果对指针的概念不熟悉,
请继续读下去,在本章的后面要详细地介绍)。与A n s i S t r i n g和Wi d e S t r i n g类
型不同,P C h a r的内存不是由Object Pascal自动产生和管理的,要用O b j e c t
P a s c a l的内存管理函数来为P C h a r所指向的内存进行分配。P C h a r字符串的
理论最大长度是4 G B,P C h a r变量在内存中的分布见图2 - 3。
3 0 第一部分快速开发的基础
下载
图2-3 PChar的内存分布
提示在大多数情况下,AnsiString类型能被用成PChar,应该尽可能地使用AnsiString,因为它
对字符串内存的管理是自动,极大地减少了应用程序中内存混乱的错误代码,因此,要尽可能
地避免用PChar类型以及对它相应进行人工分配内存。
正如在前面所提到的, P C h a r变量需要人工分配和释放存放字符串的内存。通常,用S t r A l l o c ( )函
数为P C h a r缓冲区分配内存,但是其他几种函数也能用来为P C h a r类型分配函数,包括A l l o c M e m ( )、
G e t M e m ( )、S t r N e w ( )和VirtualAlloc() API函数。这些函数有相应的释放内存的函数。表2 - 6列出了几个
分配内存的函数以及它们相应的释放内存的函数。
表2-6 内存分配和释放函数
内存分配函数内存释放函数
A l l o c M e m ( ) F r e e M e m ( )
G l o b a l A l l o c ( ) G l o b a l F r e e ( )
G e t M e m ( ) F r e e M e m ( )
N e w ( ) D i s p o s e ( )
S t r A l l o c ( ) S t r D i s p o s e ( )
S t r N e w ( ) S t r D i s p o s e ( )
Vi r t u a l A l l o c ( ) Vi r t u a l F r e e ( )
下面的例子演示了使用P C h a r和s t r i n g类型时的内存分配技术:
v a r
P 1 , P 2 : P C h a r ;
S 1 , S 2 : s t r i n g ;
b e g i n
P 1 : = S t r A l l o c ( 6 4 * S i z e O f ( C h a r ) ) ;
/ / P 1指向一个分配了6 3个字符的缓冲区
StrPCopy(P1,'Delphi 5');
/ /复制一组字母到P 1
S1:='Developer's Guide';
/ /在S 1中放几个字母
P 2 : = S t r N e w ( P C h a r ( S 1 ) ) ;
/ / P 2指向S 1的备份
S t r C a t ( P 1 , P 2 ) ;
/ /连接P 1和P2
S2:=P1;
//S2现在为'Delphi 5 Developer's Guide’
S t r D i s p o s e ( P 1 ) ;
/ /清除P 1和P 2的缓冲区。
S t r D i s p o s e ( P 2 ) ;
e n d .
首先注意到,在为P 1分配内存时S t r A l l o c ( )中用到的S i z e O f ( c h a r )。要记住在以后D e l p h i版本中一个
字符的长度要从一个字节变成两个字节,因此,不能假定一个字符的长度为一个字节, Sizeof() 就保
证了不管字符长度是多少都能正确地分配内存。
S t r C a t ( )用来连接两个P C h a r字符串。注意,这里不能像对长字符串和S h o r t S t r i n g类型那样用+运算
符来连接两个字符串。
S t r N e w ( )函数用来把字符串S 1中的值拷贝到P 2中,使用这个函数要小心,要避免出现内存被覆盖
的错误,因为S t r N e w ( )函数只为字符串分配足够但不浪费的内存,请看下面的例子:
v a r
P 1 , P 2 : P C h a r ;
b e g i n
P 1 : = S t r N e w (‘H e l l o’) ;
/ /只分配够P 1用的内存
P 2 : = S t r N e w (‘Wo r l d’) ;
/ /只分配够P 2用的内存
S t r C a t ( P 1 , P 2 ) ;
/ /小心:内存出现混乱了!
第2章Object Pascal语言3 1 下载
.
.
.
e n d ;
提示和其他字符串类型一样,Object Pascal也为操作P C h a r类型提供了一些操作函数和过程,
请在Delphi的联机帮助“String-handing routines(null-terminated)”。
另外,还可以在本书附带的C D - R O M的/ S o u r c e / U t i l s目录中的S t r U t i l s中找到更多的针对以n u l l结束
的字符串的过程和函数。
 
Delphi 代码优化——字符串篇
关键词:delphi, anisstring, pchar
freewizard
delphi有三种字符串类型:短字符串(string[n],n=1..255)存储区为静态分配,大小在编译时确定,这是继承于bp fordo
s的类型;字符数组(pchar)主要是为了兼容各类api,在bp7中已经出现,如今在delphi中更加应用广泛,其存储区可以用字符数组静态分配,也可用getmem手动分配;而长字符串(ansistring)是delphi独有的,其存储区在运行时动态分配,最灵活也最易被滥用。
不重复初始化
delphi默认字符串类型ansistring会自动初始化为空。如下代码:
var s:string;
begin
s:='';
……
end;
s:='';就属多此一举。但是值得注意的是这对函数返回值result无效。而一般说来,用var实参传递比返回字符串值要更快一些。
使用setlength预分配长字符串(ansistring)
动态分配内存是ansistring的一大长项,但容易弄巧成拙,一个典型的例子如下:
s2:=' ';
for i:=2 to length(s1)do
s2:=s2+s1;
且不说可用delete取代之,主要问题在于上例的循环中s2的内存区域被不停地重复分配,相当费时。一个简单有效的办法如下:
setlength(s2,length(s1)-1);
for i:=2 to length(s1)do
s2[i-1]:=s1;
这样s2内存只会重新分配一次。
字符串与动态数组的线程安全(thread safety)
在delphi 5以前动态数组与长字符串的操作这些非线程安全调用是由引用计数来处理其临界问题的,而自delphi5起就改为直接在一些临界指令前加lock指令前缀来避免这个问题。不幸的是这一修改的代价相当昂贵,因为在pentiumⅱ处理器中lock指令相当费时,大概要耗费额外的28个指令周期来完成这一操作,因而整体效率至少下降一半。
解决这个问题的办法只有一个,那就是修改delphi rtl核心代码。在备份原文件后,将source/rtl/sys/system.pas中所有的lock替换为{lock},当然必须是整字替换。
如此还未完全优化,下一步是将delphi4运行库中也有的xchg指令去掉,因为该指令有隐含的lock前缀,所以必须将system.pas内_lstrasg和_strlasg两个过程中的 xchg edx,[eax] 替换为如下代码:
mov ecx,[eax]
mov [eax],edx
mov edx,ecx
ok大功告成,编译一下,覆盖system.dcu即可。如此其执行效率将比delphi5提高6倍,比delphi4提高2倍。
避免使用短字符串
由于很多字符串操作会先把短字符串转换为长字符串,从而减慢了执行速度,因此还是少使用短字符串为妙。
避免使用copy函数
这也和滥用内存管理有关。一个典型的情形如下:
if copy(s1,23,64)=copy(s2,15,64) then
……
这样导致分配了两块临时内存,因而降低了效率。应当替换为如下代码:
i:=0;
f:=false;
repeat
f:=s1[i+23]<>s2[i+15];
inc(i);
until f or (i>63);
if not f then
……
同样的,如下语句就显得相当低效:
s:=copy(s,1,length(s)-10);
应改为
delete(s,length(s)-10,10);
顺便提一句,在连接字符串时,s:=s1+s2;简单而有效;但在delphi2下则s:=format([%s%s],s1,s2);可能稍快些。
总是使用长字符串,必要时转换为pchar
先看看ansistring的定义:
type
astring = packed record
allocsiz: longint;
//动态分配大小
refcnt: longint;
//引用计数
length: longint;
//实际长度
chrarr:array[1..allocsiz-6]of char;
//字节序列
end;
其中astring[1]将返回astring.chrarr[1]的内容。
很多人认为ansistring是天生低效的。其实这在很大程度上是由代码编写不良、内存管理乱用和缺乏支持的函数所致。如上所述,一旦被动态分配了一块内存,长字符串就成了一个线性的字节序列,并无所谓的效率问题。当然,若有更多有效的函数支持那就更好了。
说到ansistring到pchar的转换,本质上有三个办法:
(1) p:=@s[1];这会引发uniquestring调用。
(2) p:=pchar (s);这会先检查s是否为空,若是,则返回nil,否则即返回s[1]的地址。
(3) p:=pointer(s);这不会引发任何隐含调用,因而是在确定s非空情况下的最佳选择。
 
[:)] 我替chenshaizi补充 : 来自 ---> 《P a s c a l精要》 。
 
不过还是该谢谢的!
 
考虑的好不全面啊,没什么不说UCS4String?
 
后退
顶部