原文地址:http://blog.sina.com.cn/s/blog_53c1950a010158mw.htmlphp
Windows API函數MultiByteToWideChar用於多字節編碼字符串向寬字符串(即UTF-16 LE)的轉碼。它的第一個參數的經常使用值是CP_ACP和CP_OEMCP。這到底指的是什麼代碼頁呢? 我編了小程序作了實驗。
CP_ACP和CP_OEMCP,分別是指當前計算機上的Windows操做系統的Windows代碼頁與OEM代碼頁。對於東亞的簡體中文、繁體中文、日文、韓文等Win操做系統語言環境,這兩種代碼頁是同一個,如簡體中文是代碼頁936即GB2312字符集,繁體中文是950即大五碼字符集,韓文是94九、日文是932。對於西方國家的拼音文字語言設置,兩個代碼頁不一樣。典型的如English_US,其Windows代碼頁是125二、OEM代碼頁是437,還有第三個代碼頁ISO-8859-1又稱Latin-1或「西歐語言」,是針對英語法語西語德語等西歐語言的擴展ASCII字符集。這三者(125二、43七、8859-1)都是針對英語但並不相同。
爲何會有Windows代碼頁與OEM代碼頁的區別呢?由於在八十年代DOS系統時期,仍是「字符終端」的屏幕只可以顯示的256個字符,這些字符的字形的點陣信息存儲在硬件的ROM中。DOS操做系統經過系統中斷調用驅動程序把這些字形讀出來寫入顯存。這是由OEM負責字符集中有哪些字符,顯示時爲何字形的時代,並且一臺PC上只有這麼一套字符集/字形,沒得選,除非你再差一個帶字庫的「漢卡」。進入了微軟的Windows操做系統時代以後,因爲硬件的發展,操做系統有了本身的字形文件,繪製字符時再也不真地去讀ROM,而是用字形文件(就是字體fonts文件)來把字符的形狀寫入顯存。能夠選擇用哪一種字形:若有襯線的Times NewRome,仍是無襯線的Sans Serif。操做系統默認使用的字符集,就由微軟來定義了,如English_US使用Codepage1252;簡體中文使用Codepage936(即國標2312). 至於那個OEM436,就是legacy,用於向後兼容。
綜上,就這麼點事。CP_ACP和CP_OEMCP,分別是UINT的0和1。在WinNls.h中的註釋說明分別是「default to ANSI code page」,「default to OEM code page」。因此,在簡體中文Windows,這兩個宏表示的都是代碼頁936.
下述程序代碼片斷用於測試
UINT codepage=936;
char str[]="咱們中國"; //這個char[]必然是多字節編碼字符串
DWORD len;
// 獲得咱們要轉換的MyString爲UNICODE所須要的UNICODE緩衝區的長度
len = MultiByteToWideChar(codepage, 0, str, -1, 0, 0);
wchar_t *buf=new wchar_t[len+10];
MultiByteToWideChar(codepage, 0, str, -1, buf, len);
setlocale(LC_CTYPE,"");//把當前locale字符環境從C/C++缺省的"C"設置,改成操做系統的設置(即代碼頁936)
wprintf(L"%s",buf); //由於這個C標準庫函數的實現,是把寬字符輸入又轉化爲多字節字符去顯示,因此必須正確設置當前操做系統的多字節編碼的代碼頁
結果:
1. 輸入是char str[]="咱們中國"; UINT codepage=936或者54936(這是GB18030代碼頁)或者CP_ACP或者CP_OEMCP,都能正確打印出結果「咱們中國」。
2. 輸入是char str[]="иい瓣"; UINT codepage=950; 也能正確把上述大五碼字符串打印出寬字符串輸出結果「咱們中國」。
3. 輸入是char str[]="鎴戜滑涓浗 "; UINT codepage=65001; 也能正確把上述UTF-8字符串打印出寬字符串輸出結果「咱們中國」。
附錄:
一個在線GB/BIG5/UTF-8/UNICODE轉碼的網站http://www.dheart.net/bmzh/index.php
ps. 實際上,簡體中文Windows系統的默認代碼頁936,不是隻有6763個漢字的GB2316,正確說法是自1995年Windows95起,代碼頁936是GBK字符集,包含了20902個漢字。此前,代碼頁936與GB2316是同樣的。GB2316 >> GBK >> GB18030 是向後兼容的。因此編程角度把這三者視做等同,也湊合啦。html