學習Windows編程的時候,遇到字符串處理會讓人非常抓狂,當然問題的根本還是自己學藝不精,不過還是得吐槽一下,造成這一局面的原因是規則變化多端而又有點不可捉摸,這不,最近就掉到坑里面去了。
先看看下面的這段代碼:
int main(int argn,char* argv[]){ char strA[]="ABC 簡體中文"; wchar_t strW[]=L"ABC 簡體中文"; PRintf("%s/n",strA); wprintf(L"%s/n",strW); return 0;}猜猜看,輸出是什么?在我的電腦上(程序使用VS2010編譯通過,Windows 7操作系統,簡體中文版)運行的結果是這樣的:
第一個還好好地,怎么第二個會出現三個問號?
調試一下試試看,在return 0前面下斷點,然后查看內存:
這個是strA在內存中的值:41 42 43 20 bc f2 cc e5 d6 d0 ce c4 00
而strW則是:41 00 42 00 43 00 20 00 80 7b 53 4f 2d 4e 87 65 00 00
首先,我們知道char類型占一個字節,而wchar_t則是占兩個字節,前面的41,42,43,20就是分別’A’,’B’,’C’和’ ‘(空格),這里表明,寬字符采用的是Little-Endian方式存放兩個字節的,接下來我們把重點都放在漢字上面。
在strA中,表示漢字“簡體中文”數據為bc f2 cc e5 d6 d0 ce c4,而在strW則是80 7b 53 4f 2d 4e 87 65,差別很大,為什么是這樣呢?
這其中涉及到了編碼的問題。char類型中出現的漢字,采用的是GB2312的編碼規則,查詢該編碼表,可以發現,“簡”字的編碼為BCF2,“體”為CCE5,“中”為D6D0,而“文”則為CEC4,這就是strA中中文的表示方式,但是在寬字符strW中,采用的編碼則是Unicode編碼,在Windows平臺下Unicode編碼值就是UTF-16編碼值。查詢“簡體中文”四個漢字的編碼,可以發現是7B80 4F53 4E2D 6587,由于計算機的架構為Little-Endian,需要把高低位字節互換,這也就是寬字符的表示形式。
根據網頁上的說明(參考這里)C/C++標準只是聲明wchar_t是一個可以表示字符集中的任意一個字符的足夠寬的變量類型。wchar_t可以用任何encoding編碼方式來存儲這個字符,如ANSI、UCS-2或者UCS-4, 甚至是SCU-128,只不過我們通常是用unicode編碼方式。wchar_t是與實現相關的。所以為了可移植性,我們不能假定wchar_t的編碼方式,然后根據編碼方式做一些相關性操作,我們只能理解它為一個足夠寬的字符類型。
最后,我們還能順便發現,wprintf函數在處理文本輸出的時候,并不處理編碼問題,而是直接按多字節字符順序輸出。
好,現在問題的原因找到了,那么該如何解決問題呢?
Windows當然不會沒有想到這個問題,在Windows中,提供了如下兩個函數:WideCharToMultiByte和MultiByteToWideChar,他們都位于頭文件winnls.h中,分別是將寬字符轉化為多字節和將多字節轉化為寬字符。下面的例子直接給出了轉化的代碼,函數的具體使用方法可以翻閱MSDN。
int main(int argn,char* argv[]){ wchar_t strW[]=L"ABC 簡體中文"; char* pW2A; int t=0; //第一次,確定需要的字節數 t=WideCharToMultiByte(CP_ACP,0,strW,-1,NULL,0,NULL,FALSE); if(t!=0) { pW2A=(char*)malloc(t);//分配內存,然后運行第二次,注意參數區別 WideCharToMultiByte(CP_ACP,0,strW,-1,pW2A,t,NULL,FALSE); printf("%s/n",pW2A); free(pW2A); } return 0;}這回顯示就沒有什么問題了,長舒一口氣,暫時從坑里面爬出來了。
新聞熱點
疑難解答