Delphi 中的字串——《Delphi6 開發人員指南》讀書筆記 (轉)
中的字串
——《Delphi6 開發人員指南》讀書筆記
Spacesoft【暗夜狂沙】
Delphi 對字串這個結構的支援是十分豐富的,不僅有Delphi 本身支援的string 型別,還支援和C 語言相容的字串陣列。那麼他們之間有什麼區別呢?本文試圖就此做一個詳細的剖析,並且試圖回答論壇上常見的幾個問題。
首先,我們要討論的是Delphi 中的string 到底是什麼東東,因為我們在OP 的語法參考手冊上知道,Delphi 有三種string : ShortString、AnsiString (就是相容BCB 的AnsiString 的那種)以及WString (用來支援Unicode 的,其他的和AnsiString 是完全一樣的)。在預設的情況下,將把string 解釋為AnsiString ,而需要的時候,可以設定使編譯器將string 解釋為ShortString(當然,我們很少見到人要這麼做,因為AnsiString 用得很好,而ShortString 只支援255 個字元,並且和C 語言的字串陣列不相容,這個我們後面會提到),對應的編譯器指示符號是預設的{$H+} 和 {$H-}。
那麼,這三種string 到底有什麼差別呢?差別在於他們的不同結構。
對於ShortString 來說,它在中的結構可以表示為:
strShort = record
wLength: ;
szBuf: array of Char;
end;
也就是說,對ShortString 的每次操作,不需要遍歷這個字串便可以取得這個字串的大小了。另外,這個字串陣列的最後是沒有一個#0 字元作為結尾的。因此ShortString 的陣列和C 語言的字串是不相容的。
對於AnsiString 來說,根據《Delphi6 開發人員指南》的描述,它的結構可以表示如下:
strAnsi = record
nSize: Integer;
nRef: Integer;
nLength: Integer;
szBuf: array of Char;
end;
也就是說AnsiString 不僅僅儲存了本字串的長度,還儲存了對這個字串的引用數。因此,不同的AnsiString 事實上可能具有相同的實體地址,所以Delphi 的字串複製經常是驚人的。然而,當一個字串改變時怎麼辦呢?Delphi 將釋放對這個字串的引用(把nRefCount 減1),然後新建一個字串來裝載新的內容。
另外,與ShortString 不同的是,AnsiString 的字元陣列是以#0 結尾的,這樣szBuf 就可以被當成C 中的字元陣列了。估計這樣的設計是為了相容 。
WideString 和AnsiString 基本上是一樣的,所以我們討論的時候,僅僅討論AnsiString 和ShortString。
然後, 我們要說明的是,string 具有生存期管理特性。就是說,當string 超出作用域後,字串佔用的資源自動被釋放掉。這個機制是怎麼實現的呢?對於全域性變數,當然它的作用域就是它所在的Unit 的生存週期,那麼當然可以在finalization 段進行釋放了。而中的變數呢?編譯器就自動在整個函式的外面套上一個try ... finally 處理。這樣,不管什麼情況下,這些變數就總能釋放掉了。
下面一個問題是:假如現在有一個指標,它被指向一個string, 那麼它指向的東西是什麼呢?
答案是:指向szBuf 的開頭,並且ShortString 不支援這樣的強制轉換(這是很自然的,因為做這樣轉化的目的純粹就是為了和C 語言相容)。於是string[1] 就是這個字串的第一個字元。於是,“看起來”這個字串就只有那些字元了。於是,我們就可以用PChar() 強制型別轉化把一個string 轉化為一個PChar,然後傳到需要字元陣列作為引數的Win32 API 中,因為“看起來” 這個字串這個時候確實是一個標準的C 語言字串。甚至,我們可以這樣使用字串:
procedure Test();
var
strBuf: string;
begin
SetLength(strBuf, 255); //千萬不要忘了先給你的字串申請足夠的空間,不然……嘿嘿,等著彈框兒吧^_^
GetModuleFileName(0, PChar(strBuf), 255);
ShowMessage(strBuf);
end;
我們知道,這個API 的原型是這樣的:
DWORD GetModuleFileName(
HMODULE hModule, // handle to module
LPTSTR lpFilename, // Pointer to a buffer that receives the fully-qualified path for the module
DWORD nSize // size of buffer
);
這個API居然以為我們真的根據它的要求傳了一個array of Char 進去!
透過類似這樣的機制,Delphi 使它的使用者在C 語言寫的API 原型中可以自由的穿行,一點都沒有“二等公民”的感覺,而且又可以享用Delphi 本身的資料型別帶來的方便,了不起!
現在我們來總結一下Delphi 中字串型別的特點:
1、與C 語言不同,不是依靠#0 字元做字串結束標誌,而是透過字串前面的數字來記錄字串的長度(儘管為了和C 語言相容,AnsiString 的字串實現確實是在結尾放了一個#0 字元的)
2、string 是具有生存期管理特性的,當string 超出作用域後,字串佔用的資源自動被釋放掉。
3、對字串進行強制型別轉化為PChar ,會得到一個字串指標,這個字串指標的用法和C 語言中的陣列是一樣的。
對於
strBuf: string;
SetLength(strBuf, 255);
你在使用時,可以把PChar(strBuf) 看作是C 語言裡的這樣一個東西:
char strBuf[255];
記住,在上個宣告裡strBuf 是一個指標,它指向那個指標陣列的第一個字元的地址,而你做PChar(strBuf) 運算得來的指標就是這個東西。
在最後,解釋一下《開發人員指南》裡面引起過一段爭論的一句話:
“在練習將一個字串轉換為PChar型別時要小心,因為字串在超出其作用範圍時有自動回收的功能,因此當進行P:=PChar(Str)的賦值時,P的作用域(生存期)要比Str 長。”
這句話的意思是這樣的:字串型別是具有自動回收功能的,但是字串指標沒有。P:=PChar(Str)返回的指標可能在作用域之外使用,因此P 的生存週期可能比Str 要長。舉個例子來說明:
procedure getPChar(P: PChar);
var
strTmp: string;
begin
strTmp := 'aass';
P := PChar(strTmp);
end;
這個時候,明顯返回的這個指標P 的作用域要大於strTmp,那麼這個過程結束的時候,strTmp已經被自動釋放掉了。這個過程的函式得到的P 事實上已經是一個懸掛指標,沒有意義了。作者的本意是提醒讀者注意防止這樣的情況發生。
參考文獻:
1、《Delphi6 開發人員指南》,Steve Teixeira 等著,龍勁松等譯,機械工業出版社,北京,年1月第一版
2、《 Pascal 語言參考手冊》
歡迎光臨作者的個人主頁:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-984617/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 《Mastering Delphi6》學習筆記之三 (轉)AST筆記
- 《Node.js開發指南》讀書筆記Node.js筆記
- Delphi6/7 中XML 文件的應用 (轉)XML
- Delphi6的新特性[翻譯] (轉)
- C++讀書筆記:字串C++筆記字串
- 敏捷開發讀書筆記——隨筆敏捷筆記
- 號外:Delphi6新特性! (轉)
- 號外:Delphi6 新特性 !!!! (轉)
- 華為CMPP原始碼delphi6版 (轉)原始碼
- 《Git權威指南》讀書筆記Git筆記
- 面向Java開發人員的Flex開發指南JavaFlex
- 讀書筆記:RUP (轉)筆記
- 《深入核心的敏捷開發》讀書筆記(2)敏捷筆記
- boost------asio庫的使用1(Boost程式庫完全開發指南)讀書筆記筆記
- 讀書筆記-----Java中的引用筆記Java
- 每個開發人員應閱讀的9本書 - Victor Rentea
- TIJ讀書筆記(二) (轉)筆記
- TIJ讀書筆記(一) (轉)筆記
- 《Web API的設計與開發》讀書筆記WebAPI筆記
- 《LINUX與UNIX SHELL程式設計指南》讀書筆記(轉)Linux程式設計筆記
- 《IBM BPM實戰指南》讀書筆記IBM筆記
- 《IDA Pro權威指南》讀書筆記筆記
- <Laravel 開發環境部署>讀書筆記----常用指令Laravel開發環境筆記
- 《Flask Web開發》讀書筆記【Windows環境】FlaskWeb筆記Windows
- 《flask Web 開發》讀書筆記 & chapter6FlaskWeb筆記APT
- 《軟體開發本質論》讀書筆記筆記
- 《高質量C++程式設計指南》讀書筆記(一) (轉)C++程式設計筆記
- 面向 Java 開發人員的 Scala 指南: 類操作Java
- 轉載大師的讀書筆記 2筆記
- 轉載大師的讀書筆記 1筆記
- 《音視訊開發進階指南》讀書筆記(一) —— 音視訊基礎概念筆記
- 《Haskell趣學指南》讀書筆記(2):Type And TypeclassHaskell筆記
- 《高效能iOS應用開發》讀書筆記iOS筆記
- 讀書筆記:高效能PHP應用開發筆記PHP
- 軟體安全開發生命週期讀書筆記筆記
- [讀書筆記] Ruby 中的 Block 和 Iterator筆記BloC
- 讀書筆記...筆記
- 讀書筆記筆記