由于作者是美國(guó)人的緣故,我發(fā)現(xiàn)Windows下的幾本名著(如《Windows程序設(shè)計(jì)》,Jeffrey Richter的《Windows 核心編程》)對(duì)字符集的講解都不甚透徹?,F(xiàn)在這里對(duì)一些易讓人迷惑的問(wèn)題進(jìn)行澄清,并指明一些編程時(shí)容易出錯(cuò)的問(wèn)題(我自己就犯過(guò))。
先解釋幾個(gè)概念:
字符集:根據(jù)編碼特性而分,字符集可分為三類。
l 窄字符集(SBCS) 每個(gè)代碼由一個(gè)字節(jié)進(jìn)行表示,比如ANSI。
l 多字節(jié)字符集(MBCS) 字符集中的代碼或者是單字節(jié),或者是多字節(jié),比如DBCS,GB2312等。
l 寬字節(jié)字符集 字符集中每個(gè)字符由兩個(gè)字節(jié)表示。比如UNICODE
代碼頁(yè):在UNICODE和DBCS中由于包含的代碼十分多,為了使用方便就需要對(duì)這些代碼進(jìn)行組織。組織的方法就是把不同國(guó)家的代碼分別放入不同的代碼頁(yè)。
字符集與代碼頁(yè)的關(guān)系:由上可知,對(duì)于UNICODE和DBCS,代碼頁(yè)是從屬于字符集的。但對(duì)于SBCS類的字符集(比如ANSI)和DBCS之外的MBCS字符集(比如GB2312等)他們則只對(duì)應(yīng)于一個(gè)代碼頁(yè)。
下面看一段潛在有問(wèn)題的程序:
void ConverAndOutputString(HDC hdc,LPWSTR wstr, int length,int x,int y)
{
int nret;
int sizebuffer= 2*length;
char* lpBuffer=new char[sizebuffer];
nret=WideCharToMultiByte(CP_ACP,0,wstr , length,
lpBuffer, sizebuffer ,NULL,NULL);
TextOut(hdc,x,y, lpBuffer,nret);
delete[]lpBuffer;
}
這段程序很簡(jiǎn)單,只是把一個(gè)寬字符串轉(zhuǎn)為DBCS串而后按指定的坐標(biāo)進(jìn)行輸出。Jeffrey Richter在他的《Windows核心編程》中的第26頁(yè)也用幾乎的相同的方法進(jìn)行字符串轉(zhuǎn)換。但這段程序其實(shí)是有問(wèn)題的。問(wèn)題出在轉(zhuǎn)換字符串時(shí)不應(yīng)該硬編碼指定代碼頁(yè),而應(yīng)該根據(jù)當(dāng)前字體進(jìn)行動(dòng)態(tài)獲取。否則在某些情況下將無(wú)法把wstr中的UNICODE字符轉(zhuǎn)換到正確的代碼。如果你用上述代碼進(jìn)行中文輸出,你將很有幸看到很多問(wèn)號(hào)被自動(dòng)添加到你的字符串中。
解決的辦法也很簡(jiǎn)單,但首先你要熟悉如下兩個(gè)個(gè)API函數(shù):
int GetTextCharset(HDC hdc);//lpCs,dwFlags