C 字串型別說明 Win32 字元編碼

2021-05-23 02:44:04 字數 3361 閱讀 1741

引言

毫無疑問,我們都看到過像 tchar, std::string, bstr 等各種各樣的字串型別,還有那些以 _tcs 開頭的奇怪的巨集。你也許正在盯著顯示器發愁。本指引將總結引進各種字元型別的目的,展示一些簡單的用法,並告訴您在必要時,如何實現各種字串型別之間的轉換。

在第一部分,我們將介紹3種字元編碼型別。了解各種編碼模式的工作方式是很重要的事情。即使你已經知道乙個字串是乙個字元陣列,你也應該閱讀本部分。一旦你了解了這些,你將對各種字串型別之間的關係有乙個清楚地了解。

在第二部分,我們將單獨講述string類,怎樣使用它及實現他們相互之間的轉換。

字元基礎 -- ascii, dbcs, unicode

所有的 string 類都是以c-style字串為基礎的。c-style 字串是字元陣列。所以我們先介紹字元型別。這裡有3種編碼模式對應3種字元型別。第一種編碼型別是單子節字符集(single-byte character set or sbcs)。在這種編碼模式下,所有的字元都只用乙個位元組表示。ascii是sbcs。乙個位元組表示的0用來標誌sbcs字串的結束。

第二種編碼模式是多位元組字符集(multi-byte character set or mbcs)。乙個mbcs編碼包含一些乙個位元組長的字元,而另一些字元大於乙個位元組的長度。用在windows裡的mbcs包含兩種字元型別,單位元組字元(single-byte characters)和雙位元組字元(double-byte characters)。由於windows裡使用的多位元組字元絕大部分是兩個位元組長,所以mbcs常被用dbcs代替。

在dbcs編碼模式中,一些特定的值被保留用來表明他們是雙位元組字元的一部分。例如,在shift-jis編碼中(乙個常用的日文編碼模式),0x81-0x9f之間和 0xe0-oxfc之間的值表示"這是乙個雙位元組字元,下乙個子節是這個字元的一部分。"這樣的值被稱作"leading bytes",他們都大於0x7f。跟隨在乙個leading byte子節後面的位元組被稱作"trail byte"。在dbcs中,trail byte可以是任意非0值。像sbcs一樣,dbcs字串的結束標誌也是乙個單位元組表示的0。

第三種編碼模式是unicode。unicode是一種所有的字元都使用兩個位元組編碼的編碼模式。unicode字元有時也被稱作寬字元,因為它比單子節字元寬(使用了更多的儲存空間)。注意,unicode不能被看作mbcs。mbcs的獨特之處在於它的字元使用不同長度的位元組編碼。unicode字串使用兩個位元組表示的0作為它的結束標誌。

單位元組字元包含拉丁文本母表,accented characters及ascii標準和dos作業系統定義的圖形字元。雙位元組字元被用來表示東亞及中東的語言。unicode被用在com及windows nt作業系統內部。

你一定已經很熟悉單位元組字元。當你使用char時,你處理的是單位元組字元。雙位元組字元也用char型別來進行操作(這是我們將會看到的關於雙子節字元的很多奇怪的地方之一)。unicode字元用wchar_t來表示。unicode字元和字串常量用字首l來表示。例如:

wchar_t wch = l''1''; // 2 bytes, 0x0031

wchar_t* wsz = l"hello"; // 12 bytes, 6 wide characters

字元在記憶體中是怎樣儲存的單位元組字串:每個字元佔乙個位元組按順序依次儲存,最後以單位元組表示的0結束。例如。"bob"的存貯形式如下:

426f

6200bo

bbos

unicode的儲存形式,l"bob"

42 00

6f 00

62 00

00 00bo

bbos

使用兩個位元組表示的0來做結束標誌。

一眼看上去,dbcs 字串很像 sbcs 字串,但是我們一會兒將看到 dbcs 字串的微妙之處,它使得使用字串操作函式和永字元指標遍歷乙個字串時會產生預料之外的結果。字串" " ("nihongo")在記憶體中的儲存形式如下(lb和tb分別用來表示 leading byte 和 trail byte)

93 fa

96 7b

8c ea

00lb tb

lb tb

lb tb

eoseos值得注意的是,"ni"的值不能被解釋成word型值0xfa93,而應該看作兩個值93和fa以這種順序被作為"ni"的編碼。

使用字串處理函式

我們都已經見過c語言中的字串函式,strcpy(), sprintf(), atoll()等。這些字串只應該用來處理單位元組字元字串。標準庫也提供了僅適用於unicode型別字串的函式,比如wcscpy(), swprintf(), wtol()等。

微軟還在它的crt(c runtime library)中增加了操作dbcs字串的版本。str***()函式都有對應名字的dbcs版本_mbs***()。如果你料到可能會遇到dbcs字串(如果你的軟體會被安裝在使用dbcs編碼的國家,如中國,日本等,你就可能會),你應該使用_mbs***()函式,因為他們也可以處理sbcs字串。(乙個dbcs字串也可能含有單位元組字元,這就是為什麼_mbs***()函式也能處理sbcs字串的原因)

讓我們來看乙個典型的字串來闡明為什麼需要不同版本的字串處理函式。我們還是使用前面的unicode字串 l"bob":

42 00

6f 00

62 00

00 00bo

bbos

因為x86cpu是little-endian,值0x0042在記憶體中的儲存形式是42 00。你能看出如果這個字串被傳給strlen()函式會出現什麼問題嗎?它將先看到第乙個位元組42,然後是00,而00是字串結束的標誌,於是strlen()將會返回1。如果把"bob"傳給wcslen(),將會得出更壞的結果。wcslen()將會先看到0x6f42,然後是0x0062,然後一直讀到你的緩衝區的末尾,直到發現00 00結束標誌或者引起了gpf。

到目前為止,我們已經討論了str***()和wcs***()的用法及它們之間的區別。str***()和_mbs**()之間的有區別區別呢?明白他們之間的區別,對於採用正確的方法來遍歷dbcs字串是很重要的。下面,我們將先介紹字串的遍歷,然後回到str***()與_mbs***()之間的區別這個問題上來。

正確的遍歷和索引字串

因為我們中大多數人都是用著sbcs字串成長的,所以我們在遍歷字串時,常常使用指標的++-和-操作。我們也使用陣列下標的表示形式來操作字串中的字元。這兩種方式是用於sbcs和unicode字串,因為它們中的字元有著相同的寬度,編譯器能正確的返回我們需要的字元。

然而,當碰到dbcs字串時,我們必須拋棄這些習慣。這裡有使用指標遍歷dbcs字串時的兩條規則。違背了這兩條規則,你的程式就會存在dbcs有關的bugs。

C 字串完全指南 Win32字元編碼(一)

c 字串完全指南 win32字元編碼 一 前言 字串的表現形式各異,象tchar,std string,bstr等等,有時還會見到怪怪的用 tcs起頭的巨集。這個指南的目的就是說明各種字串型別及其用途,並說明如何在必要時進行型別的相互轉換。在指南的第一部分,介紹三種字元編碼格式。理解編碼的工作原理是...

C 字串完全指南 Win32字元編碼(一)

c 字串完全指南 win32字元編碼 一 2002 11 14 17 38 53 前言 字串的表現形式各異,象tchar,std string,bstr等等,有時還會見到怪怪的用 tcs起頭的巨集。這個指南的目的就是說明各種字串型別及其用途,並說明如何在必要時進行型別的相互轉換。在指南的第一部分,介...

C 字串完全指南 Win32字元編碼(一)

c 字串完全指南 win32字元編碼 一 翻譯 連波 14 11 2002 url 前言 字串的表現形式各異,象tchar,std string,bstr等等,有時還會見到怪怪的用 tcs起頭的巨集。這個指南的目的就是說明各種字串型別及其用途,並說明如何在必要時進行型別的相互轉換。在指南的第一部分,...