1. 程式人生 > >VC++寬字元TCHAR用法三

VC++寬字元TCHAR用法三

引言

毫無疑問,我們都看到過像 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來表示。例如:

1.wchar_t wch = L''1''// 2 bytes, 0x0031 2.wchar_t* wsz = L"Hello"// 12 bytes, 6 wide characters

字元在記憶體中是怎樣儲存的

單位元組字串:每個字元佔一個位元組按順序依次儲存,最後以單位元組表示的0結束。例如。"Bob"的存貯形式如下:

42 6F 62 00
B o b BOS

Unicode的儲存形式,L"Bob"

42 00 6F 00 62 00 00 00
B o b BOS

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

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

93 FA 96 7B 8C EA 00
LB TB LB TB LB TB EOS
EOS

值得注意的是,"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 00
B o b BOS

因為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。

1.在前向遍歷時,不要使用++操作,除非你每次都檢查lead byte;

2.永遠不要使用-操作進行後向遍歷。

我們先來闡述規則2,因為找到一個違背它的真實的例項程式碼是很容易的。假設你有一個程式在你自己的目錄裡儲存了一個設定檔案,你把安裝目錄儲存在登錄檔中。在執行時,你從登錄檔中讀取安裝目錄,然後合成配置檔名,接著讀取該檔案。假設,你的安裝目錄是C:\Program Files\MyCoolApp,那麼你合成的檔名應該是C:\Program Files\MyCoolApp\config.bin。當你進行測試時,你發現程式執行正常。

現在,想象你合成檔名的程式碼可能是這樣的:

01.bool GetConfigFileName ( char* pszName, size_t nBuffSize ) 02.{ 03.char szConfigFilename[MAX_PATH]; 04. 05.// Read install dir from registry... we''ll assume it succeeds. 06. 07.// Add on a backslash if it wasn''t present in the registry value. 08.// First, get a pointer to the terminating zero. 09.char* pLastChar = strchr ( szConfigFilename, ''\0'' ); 10. 11.// Now move it back one character. 12.pLastChar--; 

相關推薦

VC++字元TCHAR用法

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

oracle 函數的用法()

order 全局 接收 報錯 sysdate times 變量 pda was -- 函數 1.oracle自帶的標準函數 to_date,to_number2.自定義函數 -- 自定義函數語法 1 CREATE OR REPLACE FUNCTION FUNCTION_

TCHAR用法

sizeof 編譯 top http 字符處理 編碼 頭文件 程序 signed TCHAR 就是當你的字符設置為什麽就是什麽例如:程序編譯為 ANSI, TCHAR 就是相當於 CHAR當程序編譯為 UNICODE, TCHAR 就相當於 WCHAR char :單字節變

多位元組字元字元

多位元組字符集——每個字元的編碼寬度不一,可為一個位元組或多個位元組。  (1)ASCII字元只佔一個位元組  (2)對於中文、日文等用兩個位元組  (3)一個字串中,如何區分哪個是中文字元,那個是ASCII字元呢?  “Windows程式設計”16進

普通字元字元之間轉換函式

以下函式會在內部分配記憶體,需要呼叫程式呼叫delete釋放記憶體: namespace _com_util {     // Convert char * to BSTR     //     BSTR __stdcall Con

關於mysql的sql語句中` `字元用法 關鍵字等處理

SELECT * FROM   `table`   WHERE `from` = 'abc' ; 當你的資料表的表名(上面的表名是table)或者欄位名字(上面的欄位名是from)是關鍵字的時候,這時就會有衝突了,mysql的轉移字元是  &

字元裝置驅動()中斷框架

目錄 字元裝置驅動(三)中斷框架 引入 彙編處理 拷貝向量表 向量表巨集解析 跳轉函式 C函式處理 asm_do_IRQ __set_irq_handler s3c24

字元UTF-8轉窄字元ANSI(使用tinyxml2亂碼問題)

使用tinyxml2讀取UTF-8編碼的XML時,中文亂碼,tiny沒有類似於QString::tostdwstring的方法,需要幾己轉換一下。 對網上搜索的結果不甚滿意,自己重寫了一個方法。 std::string UTF8ToGBK( const char *iUTF8 ) { //

Linux C語言環境下如何輸出字元 -- 轉載

                自己整理如下C++#include <iostream>#include <string>#include <locale>using namespace std;int main(void) {  wstring w = L"Out中文";

VC char和TCHAR之間轉換

                char:計算機程式語言(c、c++、java、VFP等)中可容納單個字元的一種基本資料型別。TCHAR:為了滿足Unicode編碼,對char的擴充套件,即_T(“str”)表示TCHAR型別C++支援兩種字串,即常規的ANSI編碼(使用""包裹)和Unicode編碼(使用L

字元wchar_t和窄字元char區別和相互轉換

轉自:http://blog.csdn.net/nodeathphoenix/article/details/7416725   1.    首先,說下窄字元char了,大家都很清楚,就是8bit表示的byte,長度固定。char字元只能表示ASII碼

字元和窄字元的一個坑

學習Windows程式設計的時候,遇到字串處理會讓人非常抓狂,當然問題的根本還是自己學藝不精,不過還是得吐槽一下,造成這一局面的原因是規則變化多端而又有點不可捉摸,這不,最近就掉到坑裡面去了。 先看看下面的這段程式碼: int main(int argn,char* a

字元和普通字元的區別

在我們常用的型別string和char中,對中文支援並不是很好。在這兩種型別中,中文都是兩個位元組,也就是說中文的漢字要佔用兩個位置,舉個簡單的例子,一個“漢”字用一個char是無法表示的,即    char c = '漢' ;  是錯誤的,必須用 char c[3]  =

matplotlib的基本用法()——調整座標軸

文章作者:Tyan 部落格:noahsnail.com  |  CSDN  |  簡書 本文主要是關於matplotlib的一些基本用法。 Demo import matplotlib.

字元(unicode)和多位元組的轉換(std::string與std::wstring轉換)

#include <string> #include <windows.h> using namespace std; //Converting a WChar string to a Ansi string std::string W

字元wchar_t和窄字元char區別

1.    首先,說下窄字元char了,大家都很清楚,就是8bit表示的byte,長度固定。char字元只能表示ASII碼錶中的256個字元,包括前128個可見字元和後面的128個不可見字元。        而wchar_t則是因為char所能表示的字元數太少(256個)而

到底是字元還是多字元?到底是位元組還是多位元組?

多位元組-multibyte寬字元-widechar非英語系的大部分語言,存在無法用有限的ascii字元表達的問題。由此產生了使用多位元組字元來表示的辦法,比如GB編碼的漢字。但多位元組帶來的一個顯著不便就是多位元組字元在處理的時候不太方便。比如文字編輯的時候,中英文混排,游

C++ 窄字元轉換為字元

wstring A2W(const string &s) { const char * szSource = s.c_str(); size_t _Dsize = MultiByteToWideChar(CP_ACP,0,szSource

Windows資料型別以及字元

Windows API自行定義了一些關鍵字,用來定義Windows中函式中的有關引數和返回值的大小和意義,通常將它們看作Windows的資料型別。其中較常用的有: 關鍵字             

徹底解密C++字元:1、從char到wchar_t

<本文PDF文件下載>“這個問題比你想象中複雜”(我也學下BS的風格,雖然這句話是我自己臨時想說的。^^)從字元到整數char是一種整數型別,這句話的含義是,char所能表示的字元在C/C++中都是整數型別。好,接下來,很多文章就會舉出一個典型例子,比如,'a