ASCII、ANSI、MBCS、UNICODE字符集

1. 三種計算機字符集

計算機字符集可歸類爲三種,單字節字符集(SBCS)、多字節字符集(MBCS)和寬字符集(即Unicode字符集)。

單字節字符集(SBCS):

單字節字符集,稱之爲SBCS,它的所有字符都只有一個字節的長度。常見字符集有:ASCII碼和擴展ASCII碼。SBCS字符串由一個零字節結尾,數據類型是char。

ASCII碼:
計算機發明後,爲了在計算機中表示字符,人們制定了一種編碼,叫ASCII碼。
ASCII碼由一個字節中的7位(bit)表示,最高位空着,範圍是0x00 - 0x7F 共128個字符。他們以爲這128個數字就足夠表示abcd…ABCD…1234…這些字符了。

擴展ASCII碼:
咳…說英語的人就是“笨”!後來他們突然發現,如果需要按照表格方式打印這些字符的時候,缺少了“製表符”。於是又擴展了ASCII的定義,使用一個字節的全部8位(bit)來表示字符了,這就叫擴展ASCII碼。範圍是0x00-0xFF共256個字符。

多字節字符集(MBCS):

咳…說中文的人就是聰明!中國人利用連續2個擴展ASCII碼的擴展區域(0xA0以後)來表示一個漢字,該方法的標準叫GB-2312(國標),之後又擴展出GBK和GB18030。後來,日文、韓文、阿拉伯文、臺灣繁體…都使用類似的方法擴展了本地字符集的定義, 現在統一稱爲 MBCS字符集(多字節字符集,既用多個字節表示一個字符)。其實最常見的還是用2個字節表示一個字符,稱爲DBCS(雙字節字符集)。此類常見字符集有gb2312(中國),big5(中國臺灣地區),jis(日本)…。多字節字符集(MBCS)兼容單字節字符集(SBCS),通常並不區分他們。同SBCS一樣,MBCS字符串也由一個零字節結尾,數據類型也是char。 但這個方法是有缺陷的,因爲各個國家地區各自定義的字符集免不了會有交集。因此使用GB-2312的軟件,就不能在BIG-5的環境下運行(顯示亂碼)。

ANSI編碼:

爲使計算機支持更多語言,通常使用 0x80~0xFF 範圍的 2 個字節來表示 1 個字符。比如:漢字 ‘中’ 在中文操作系統中,使用 [0xD6,0xD0] 這兩個字節存儲。
不同的國家和地區制定了不同的標準,由此產生了 GB2312、GBK、GB18030、Big5、Shift_JIS 等各自的編碼標準。這些使用多個字節來代表一個字符的各種漢字延伸編碼方式,稱爲 ANSI 編碼。在簡體中文Windows操作系統中,ANSI 編碼代表 GBK 編碼;在繁體中文Windows操作系統中,ANSI編碼代表Big5;在日文Windows操作系統中,ANSI 編碼代表 Shift_JIS 編碼。
不同 ANSI 編碼之間互不兼容,當信息在國際間交流時,無法將屬於兩種語言的文字,存儲在同一段 ANSI 編碼的文本中。
ANSI編碼表示英文字符時用一個字節,表示中文用兩個或四個字節。

寬字符集(Unicode字符集):

咳…說英語的人終於變“聰明”一些了。爲了把全世界所有的文字符號都統一進行編碼,於是制定了UNICODE字符集。標準的UNICODE字符集(即UCS-2,又稱UTF-16)規定使用2個字節表示一個字符,這下終於好啦,全世界任何一個地區的軟件,可以不用修改地就能在另一個地區運行了。Unicode字符數據類型有:WCHAR、_wchar_t、OLECHAR。
舉個例子,假如你編寫了一個Unicode的軟件,它顯示一個字符串”中國,崛起!”,然後你把這個軟件拿到日本去,日本人運行看到的也是”中國,崛起!”,只不過他不一定看的懂(不認識中文),但至少不會像MBCS字符集那樣是亂碼。
但是,標準的UTF-16並不兼容ASCII編碼(在基於ascii的編碼方案中,一個8位的0x0總是表示一個字符串的結束的,而UTF-16則不然,它的一個字符完全有可能在高8位或者低8位上等於0x0,這會導致很多應用程序錯誤,尤其是在網絡傳輸協議當中可能導致大量的字符串錯誤截斷)。
爲了兼容ASCII編碼並方便數據的傳輸,後來又提出了UTF-8新方案,UTF-8用1到6位(注意不是字節)的變長字節(究竟多少字節不確定)表示一個字符,並且變長字節也最大限度節約了數據佔用的字節數。再後來擴展方案UTF-32也提出來了,它用4個字節表示一個字符(這個用的少不管了)。

通常開發環境默認的就使用多字節字符集(MBCS)之一,比如我們中國的默認就使用GB2312字符集,畢竟它是本地字符集,比Unicode字符集(外來的和尚)更常用。Unicode常用於COM和Windows NT內。又因爲ASCII字符集被兼容,可以認爲在我們的程序中不是使用的MBCS字符集就是Unicode。

2.字符集的構成:Charset + Encoding

字符集包括兩部分:字符的集合(Charset)和編碼方案(Encoding)。字符的集(Charset)定義了該字符集內所有的字符本身;編碼方案(Encoding)定義了在計算機上表示這些字符的規範(每個字符佔幾個字節等等問題)。
通常當我們提到GB2312時,是說字符集合是GB2312的,編碼方案也是GB2312的,簡單的情況的確如此,字符集等於編碼,編碼等於字符集。但Unicode是個例外,因爲雖然Unicode的字符集合只有一個:Unicode字符集(Charset),但是編碼方案它有多個:UTF-8,UTF-16(標準方案),UTF-32都是。因此,我們必須明確一個概念,UTF-8是 unicode字符集的一個編碼方案,當我們在說到UTF-8字符和Unicode字符的時候,在某些情況下,它們在邏輯上是等價的,但是,他們並不是同一個東西,因爲Unicode字符在二進制上還有一個選擇就是原生的UTF-16編碼。

3.代碼頁

然後,需要解釋一下Codepage-代碼頁,百度百科上說代碼頁是字符集編碼的別名。你在安裝比如Window操作系統的時候若干代碼也會隨之安裝到電腦上,比如codepage936代碼頁是簡體中文,codepage950代碼頁是繁體中文,codepage932代碼頁是日文…,對於我們來說codepage936簡體中文代碼頁就是電腦上默認使用的。
再具體說codepage實際是一個從unicode到其他mbcs的轉換索引表,我們知道,windows操作系統是完全基於unicode的,正是通過代碼頁應用程序可以在unicode和本地字符集(如gb2312)之間來回轉換。
舉個例子,如果我們寫了下面的程序:

#include <windows.h>
#include <stdio.h>

int main( void )
{
  SetConsoleOutputCP(936); //指定程序使用的代碼頁,我們中國默認使用936
  printf("簡體中文\n");
  return 0;
}

程序運行結果顯示正常:簡體中文;
如果我們將main內的第一行的936改成其他的比如437(美國英語),那麼將會顯示亂碼。
原因是程序在編譯鏈接後生成的exe文件內全是01二進制數據,而這些二進制數據正是按Unicode編碼方式保存下來的。就是說當編譯器看到”簡體中文”這個字符串,它會將這4個字符按程序當前使用的代碼頁(默認936,可在程序中指定其他的)映射成一串Unicode碼01110…之類的保存到exe內。然後當我們運行exe時,Windows系統再將exe內的那串Unicode根據操作系統默認的代碼頁(也是936)再從Unicode映射回本地字符集。

4.程序中使用各種字符集

const char * p = "Hello"; // 使用 ASCII 字符集 
const char * p = "你好";  // 使用 MBCS 字符集,由於 MBCS 完全兼容 ASCII,多數情況下,我們並不嚴格區分他們 
LPCSTR p = "Hello,你好";  // 意義同上 

const WCHAR * p = L"Hello,你好"; // 使用 UNICODE 字符集(L用來定義UNICODE字符串,L就是轉換成寬字符)
LPCOLESTR p = L"Hello,你好";     // 意義同上 

const TCHAR * p = _T("Hello,你好"); // 如果預定義了_UNICODE,則表示使用UNICODE字符集;如果定義了_MBCS,則表示使用 
LPCTSTR p = _T("Hello,你好");       // 意義同上 

  在上面的例子中,T是非常有意思的一個符號(TCHAR、LPCTSTR、LPTSTR、_T()、TEXT()、_TEXT()…),它表示使用一種中間類型,既不明確表示使用 MBCS,也不明確表示使用 UNICODE。那到底使用哪種字符集那?嘿嘿…編譯的時候決定吧。設置條件編譯的方式是:VC6中,”Project\Settings…\C/C++卡片 Preprocessor definitions” 中添加或修改_MBCS、_UNICODE。爲了程序的可移植性,建議使用T類型!

轉載:http://blog.sina.com.cn/s/blog_694aab1b0100rauw.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章