字符串在編程中是一個(gè)常見的類型,但左一個(gè)類型,右一個(gè)類型可能把許多人都弄迷糊了。我寫這篇文章,試圖給大家理清 Delphi / C++ Builder 中的字符串類型。關(guān)于這些字符串類型的歷史,我們就不再啰嗦,歷史就是歷史,現(xiàn)在我們面對(duì)現(xiàn)實(shí)。
- String 類型
String 類型在 Delphi / C++ Builder 不同的版本中,對(duì)應(yīng)于不同的類型,它們的分隔線是 Delphi / C++ Builder 2009。在 2009 以前,String 類型映射到了 AnsiString,而在 ≥ 2009 版本及以后,String 類型映射到了 UnicodeString。
- ShortString 類型
ShortString 是 Delphi 中的一個(gè)短字符串類型,最大長度為 255 個(gè)字符。它的編碼方式和下面的 AnsiString 一致。
- AnsiString 類型
AnsiString 類型是一種基于引用計(jì)數(shù)的字符串類型,它實(shí)際是代碼頁為 CP_ACP (0) 的字符串類型。在傳遞參數(shù)時(shí),直接增加的是字符串的引用計(jì)數(shù),而不是復(fù)制字符串的內(nèi)容,所以效率會(huì)比較高。英文數(shù)字和字符占用 1 個(gè)字節(jié),中文占用 2 或 4 個(gè)字節(jié),絕大部分中文占用的是 2 個(gè)字節(jié)。
- Utf8String 類型
Utf8String 在 2009 以前的版本,被直接映射到了 AnsiString 上。而在 2009 及以后,Utf8String 是代碼頁為 CP_UTF8(65001)編碼的字符串類型。所以它也是一個(gè)基于引用計(jì)數(shù)的類型。英文數(shù)字和字符占用1個(gè)字節(jié),中文一般占用 2 到 4 個(gè)字節(jié),按 UTF8 規(guī)范最多占用 6 個(gè)字節(jié)。
- WideString 類型
WideString 是 Unicode 16 LE 編碼的字符串,它是 COM 兼容的類型。當(dāng)它做為一個(gè)參數(shù)傳遞時(shí),它需要?jiǎng)?chuàng)建一份值拷貝,所以效率上要稍差。其中的每一個(gè)字符的類型都是 Delphi 中的 WideChar 或 C++ Builder 中的 wchar_t。對(duì)于 Unicode 16 LE 編碼字符,我們需要注意擴(kuò)展區(qū)字符,一個(gè)非擴(kuò)展區(qū)字符占用 2 個(gè)字節(jié),而擴(kuò)展區(qū)的字符占用 4 個(gè)字節(jié)。擴(kuò)展區(qū)字符的編碼首個(gè)字符的編碼范圍是 0xD800 ~ 0xDBFF,第二個(gè)字符的編碼范圍是 0xDC00 ~ 0xDFFF。
- UnicodeString 類型
UnicodeString 是從 2009 開始引入的字符串類型,它也是基于引用計(jì)數(shù)的,所以效率上要比 WideString 快的多。我們可以認(rèn)為它是 WideString 的引用計(jì)數(shù)版本,對(duì)應(yīng)的也是Unicode 16 LE 編碼的字符串。而且 2009 開始將 String 類型映射到 UnicodeString。它的編碼方式和范圍同 WideStrnig。
- RawString 類型
RawString 實(shí)際是一種新的字符串類型,它實(shí)際上是一種沒有任何內(nèi)部編碼的字符串類型。它只是一個(gè)容器,內(nèi)部的字符編碼沒有具體約定。
- std::string
這個(gè)是 C++ 里的字符串類型,用于支持非 Unicode 16 LE 字符串,實(shí)際上是 basic_string<char>??梢哉J(rèn)為它是 Delphi 中 AnsiString 的 C++ 原生版本,不過要明白,它沒有引用計(jì)數(shù)。
- std::wstring
這個(gè)是 C++ 里的字符串類型,用于支持 Unicode 16 LE 編碼字符串,實(shí)際上是 basic_string<wchar_t>。可以認(rèn)為它是 Delphi 中 WideString 的 C++ 原生版本。
- PAnsiChar / char *
Ansi 編碼的字符串指針類型。AnsiString、Utf8String、std::string 的內(nèi)容都可以轉(zhuǎn)換成這種字符串指針類型。由于 ShortString 不是一種以 ASCII 碼 0 為結(jié)束的字符串,不符合 C 語言中的字符串規(guī)則,所以,一般情況下,我們需要先將 ShortString賦值給 AnsiString 然后才能轉(zhuǎn)換為這種指針類型。
- PWideChar / wchar_t *
Unicode 編碼的字符串指針類型。WideString、UnicodeString、std::wstring 的內(nèi)容都可以轉(zhuǎn)換成這種字符串類型。
好了,前面說了那么多,那么這些字符串類型之間如何進(jìn)行相互轉(zhuǎn)換呢?
- AnsiString <-> Utf8String / WideString / UnicodeString 類型轉(zhuǎn)換
直接賦值即可,不需要額外的處理,也不會(huì)出現(xiàn)亂碼。反過來則由于可能字符集的支持問題,造成亂碼。
- AnsiString -> PAnsiChar/char *
Delphi 中直接用 PAnsiChar(變量名) 即可,而 C++ 中使用 變量名.c_str() 函數(shù)來返回首個(gè)字符的地址。
- WideString / UnicodeString -> PWideChar / wchar_t *
Delphi 中直接用 PWideChar(變量名)即可,而 C++ 中使用 變量名.c_str() 或 變量名.c_bstr() 函數(shù)來返回首個(gè)字符的地址。
- ShortString -> PAnsiChar/char *
不好意思,此路不通。原因前面說了,所以賦值給一個(gè) AnsiString 然后再按前面的方法轉(zhuǎn)才是正道。
- std::string -> char *
STL 的標(biāo)準(zhǔn)方法 變量名.begin() 就是了。
- std::wstring -> wchar_t *
同上,STL里的 變量名.begin() 就是了。
反過來,我們將 PAnsiChar / char * 或 PWideChar / wchar_t * 類型賦值給其它類型時(shí),直接賦值就可以了。
在這里我還要提醒一點(diǎn),2009 以前版本的 Utf8String 實(shí)際上是 AnsiString 的別名,所以不要想當(dāng)然的認(rèn)為其中存貯的就是 UTF-8 編碼的字符串。
另外,在 FMX 環(huán)境下,AnsiString、WideString和Utf8String 這三個(gè)類型默認(rèn)都消失不見了,所以對(duì)應(yīng)的 PAnsiChar 也就沒有定義了。取而代之的是:MarshaledAString 等價(jià)于 PAnsiChar,而 MarshaledString 等價(jià)于 PWideChar,可以用在需要的場合。
如果有什么疑問或補(bǔ)充,我們回頭在群里聊。



