Delphi有三種類型的字符:
•AnsiChar這是標準的1字節的ANSI字符,程序員都對它比較熟悉。
•WideChar這是2字節的Unicode字符。
•Char在目前相當於AnsiChar,但在Delphi以後版本中相當於WideChar。
記住因爲一個字符在長度上並不表示一個字節,所以不能在應用程序中對字符長度進行硬編碼,而應該使用Sizeof()函數。
注意Sizeof()標準函數返回類型或實例的字節長度。
字符串是代表一組字符的變量類型,每一種語言都有自己的字符串類型的存儲和使用方法。
Pascal類型有下列幾種不同的字符串類型來滿足程序的要求:
•AnsiString這是Pascal缺省的字符串類型,它由AnsiChar字符組成,其長度沒有限制,同時與null結束的字符串相兼容。
•ShortString保留該類型是爲了向後兼容Delphi1.0,它的長度限制在255個字符內。
•WideString功能上類似於AnsiString,但它是由WideChar字符組成的。
•PChar指向null結束的Char字符串的指針,類似於C的char*或lpstr類型。
•PAnsiChar指向null結束的AnsiChar字符串的指針。
•PWideChar指向null結束的WideChar字符串的指針。
缺省情況下,如果用如下的代碼來定義字符串,編譯器認爲是AnsiString字符串:
1.AnsiString類型
AnsiString(或長字符串)類型是在Delphi2.0開始引入的,因爲Delphi1.0的用戶特別需要一個容易使用而且沒有255個字符限制的字符串類型,而AnsiString正好能滿足這些要求。
雖然AnsiString在外表上跟以前的字符串類型幾乎相同,但它是動態分配的並有自動回收功能,正是因爲這個功能AnsiString有時被稱爲生存期自管理類型。ObjectPascal能根據需要爲字符串分配空間,所以不用像在C/C++中所擔心的爲中間結果分配緩衝區。另外,AnsiString字符串總是以null字符結束的,這使得AnsiString字符串能與Win32API中的字符串兼容。實際上,AnsiString類型是一個指向在堆棧中的字符串結構的指針。
AnsiString字符串類型有引用計數的功能,這表示幾個字符串都能指向相同的物理地址。因此,複製字符串因爲僅僅是複製了指針而不是複製實際的字符串而變得非常快。當兩個或更多的AnsiString類型共享一個指向相同物理地址的引用時,Delphi內存管理使用了copy-on-write技術,一個字符串要等到修改結束,才釋放一個引用並分配一個物理字符串。下面的例子顯示了這些概念:
var
S1,S2:string;
begin
//給S1賦值,S1的引用計數爲1
S1:='Andnowforsomething...';
S2:=S1;//現在S2與S1指向同一個字符串,S1的引用計數爲2
//S2現在改變了,所以它被複制到自己的物理空間,並且S1的引用計數減1
S2:=S2+'completelydifferent1';
end;
Win32的兼容
正如前面所提到,AnsiString字符串總是null結束的。因此,它能跟以null結尾的字符串兼容,這就使得調用Win32API函數或其他需要PChar型參數的函數變得容易了。只要把一個字符串類型強制轉換爲PChar類型。下面的代碼演示了怎樣調用Win32的GetWindowsDirectory()函數,這個函數需要一個PChar類型的參數:
var
S:String;
begin
SetLength(S,256);//重要!首先給字符串分配空間
//調用API函數,S現在包含目錄字符串
GetWindowsDirectory(PChar(S),256);
如果使用了將AnsiString字符串強制轉換爲PChar類型的函數和過程,在使用結束後,要手工把它的長度恢復爲原來以null結束的長度。STRUTILS單元中的RealizeLenght()函數可以實現這一點:
procedureRealizeLength(varS:string);
begin
SetLength(S,StrLen(PChar(S)));
end;
調用ReallizeLength():
var
S:string;
begin
SetLength(S,256);//重要!首先給字符串分配空間
//調用函數,S現在包含目錄字符串
GetWindowDirectory(PChar(S),256);
RealizeLength(S);//設置S的長度爲null結束的長度
end;
跟AnsiString類型字符串不一樣,ShortString跟以null結尾的字符串不兼容,正因爲這樣,用ShortString調用Win32函數時,要做一些工作。下面這個ShortStringAsPChar()函數是在STRUTILS.PAS單元中定義的。
funcfunctionShortStringAsPChar(varS:ShortString):PChar;
{這函數能使一個字符串以null結尾,這樣就能傳遞給需要PChar類型參數的Win32API函數,如果字符串超過254個字符,多出的部分將被截掉}
begin
ifLength(S)=High(S)thenDec(S[0]);{如果S太長,就截取一部分}
S[Ord(Length(S))+1]:=#0;{把null加到字符串的最後}
Result:=@S[1];{返回PChar化的字符串}
end;
Win32API函數需要以null結尾的字符串,不要把ShortString字符串傳遞給API函數,因爲編譯器將報錯,長字符串可以傳遞給Win32API函數。
2.WideString類型
WideString類型像AnsiString一樣是生存期自管理類型,它們都能動態分配、自動回收並且彼此能相互兼容,不過WideString和AnsiString的不同主要在三個方面:
•WideString由WideChar字符組成,而不是由AnsiChar字符組成的,它們跟Unicode字符串兼容。
•WideString用SysAllocStrLen()API函數進行分配,它們跟OLE的BSTR字符串相兼容。
•WideString沒有引用計數,所以將一個WideString字符串賦值給另一個WideString字符串時,就需要從內存中的一個位置複製到另一個位置。這使得WideString在速度和內存的利用上不如AnsiString有效。
就像上面所提到的,編譯器自動在AnsiString類型和WideString類型的變量間進行轉換。示例如下:
var
W:wideString;
S:string;
begin
W:='Margaritaville';
S:=W;//wideString轉換成AnsiString
S:='ComeMonday';
W:=S;//AnsiString轉換成WideString
end;
爲了能靈活地運用WideString類型,ObjectPascal重載了Concat()、Copy、Insert()、Length()、Pos()和SetLength()等例程以及+、=和<>等運算符。
就像AnsiString和ShortString類型一樣,能用數組的下標來訪問WideString中一個特定的字符:
var
W:WideString;
C:WideChar;
begin
W:='EbonyandIvorylivinginprefectharmony';
C:=W[Length(W)];//C包含W字符串的最後一個字符
end;
以null結束的字符串
正如前面所提到的,Delphi有三種不同的以null結束的字符串類型:PChar、PAnsiChar和PWideChar。它們都是由Delphi的三種不同字符組成的。這三種類型在總體上跟PChar是一致的。PChar之所以保留是爲了跟Delphi1.0和Win32API兼容,而它們需要使用以null結束的字符串,PChar被定義成一個指向以null(零)結束的字符串指針與AnsiString和WideString類型不同,PChar的內存不是由ObjectPascal自動產生和管理的,要用Object Pascal的內存管理函數來爲PChar所指向的內存進行分配。PChar字符串的理論最大長度是4GB。
在大多數情況下,AnsiString類型能被用成PChar,應該儘可能地使用AnsiString,因爲它對字符串內存的管理是自動,極大地減少了應用程序中內存混亂的錯誤代碼,因此,要儘可能地避免用PChar類型以及對它相應進行人工分配內存。
正如在前面所提到的,PChar變量需要人工分配和釋放存放字符串的內存。通常,用StrAlloc()函數爲PChar緩衝區分配內存,但是其他幾種函數也能用來爲PChar類型分配函數,包括AllocMem()、GetMem()、StrNew()和VirtualAlloc()API函數。這些函數有相應的釋放內存的函數。