###ASCⅡ碼#程序員
在ASCⅡ碼制定的過程當中,對於代碼是六、七、8位爭議不斷,因爲可靠性的緣由,捨棄了6位,而因爲成本問題(上世紀60年代來講,8位代價是很是昂貴的),選擇了7位編碼。因而最後代碼共有26個小寫字母,26個大寫字母,10個數字,32個符號,33個控制碼,一個空格碼,共128個代碼組成了ASCⅡ碼,成爲了全球標準。windows
在小型計算機發展時期,8位一字節的標準獲得鞏固,因而決定以一個字節來儲存字符,也就是8位編碼,這樣就有了128個額外的字符來補充ASCⅡ。函數
###多字節字符集DBCS#編碼
256字符的字符集難以知足如中文、日文、韓文以及世界各個國家的各類文字需求,因而產生了多字節字符集(DBCS)。DBCS前128個代碼就是ASCⅡ碼,而較高的128箇中有些還跟隨有第二個字節,這兩個字節在一塊兒表示一個單獨的字符,如一個漢字。指針
DBCS的問題在於,有些字符是單個字節組成的,例如ASCⅡ碼,有些字符是兩個字節組成的,這致使了字符串的字符長度不能由字節數量決定,字符串的長度須要解析後才知道,每一個字節都要被檢查是否是雙字節的前導字節。code
###Unicode字符集#內存
很明顯的是,DBCS是一種很笨的解決方法,也產生了不少問題。做爲程序員,咱們知道,與其混合使用1字節和2字節代碼的DBCS,倒不如用一種全都是2字節16位編碼的字符集,這就是Unicode字符集。字符串
Unicode被認爲是「寬字符」,每一個Unicode的字符是16位而不是8位,在多字節字符集裏咱們仍處理8位字符,而在Unicode字符集裏咱們再也不處理8位字符。最開始的128個Unicode字符(0x0000到0x007F)是ASCⅡ碼,而以後的128個Unicode字符(0x0080到0x00ff)是ASCⅡ碼的擴展碼。希臘字母表從0x0370到0x03ff,漢語日語韓語從0x3000到0x9FFF代碼。擴展
Unicode的優勢是隻有一個字符集,避免了二義性,而其缺點是內存佔比是ASCⅡ的兩倍。數據類型
如今再來看char和wchar_t:
char a = 'A'; //定義了一個被0x41初始化的一個字節存儲空間 char *p = "hello!"; //windows是32位系統,指針p佔用4個字節空間存儲p的地址 //字符串hello!存儲在指針p指向的內存地址及其後6個字節,共7字節 //包括'h''e''l''l''o''!''\0' int s = strlen(p); //s=6; 記住這裏 wchar_t wa = 'A'; //定義了一個被0x0041初始化的兩個字節存儲空間 wchar_t *wp = L"hello!"; //L表明了是寬字節字符,這裏,hello!包括最後的\0共佔用了14個字節 int s = strlen(wp); //s=1; 由於strlen接受的是8位字符,它把h也就是0x0068 //分爲了0x68和0x00(內存存儲順序是高位高地址,低位低地址) //當讀完0x68後,strlen判斷讀到0x00也就是字符串結束符,就結束輸出了
wchar_t用了2個字節來存儲字符,因此大部分處理char類型的函數都不能正常工做了,可是咱們有代替的,好比strlen的寬字節版本wcslen。在strlen定義的位置,也就是STRING.H中,strlen的聲明以下:
size_t __cdecl strlen(cosnt char*);
而wcslen聲明在了WCHAR.H中:
size_t __cdecl wcslen(const wchar_t*);
因此求wp的長度應該寫爲:
int s = wcslen(wp); //求得s=6,即爲wp中字符個數
幾乎全部的字符函數都有寬字符版本,例如printf的寬字符版本爲sprintf,這些都定義在了WCHAR.H中。
###關於TCHAR.H#
Unicode也有不少的缺點,好比空間的佔用以及某些方面的不兼容等等,咱們但願維護兩個版本,一個用ASCⅡ碼而另外一個用Unicode字符集,但並不但願建立兩套源代碼文件,因此有了TCHAR.H頭文件。TCHAR爲須要字符或字符串做爲參數的普通庫函數(例如printf,strlen,sprintf,wcslen)提供了一系列的替代名稱(例如_tprintf,_tcslen),這些名稱是「通用」的,由於他們能夠指Unicode和非Unicode版本函數。
因爲TCHAR不是標準的一部分,因此定義的每一個函數和宏都有一個下劃線前綴。
定義方式以下:
#ifdef UNICODE #define _tcslen wcslen #else #define _tcslen strlen
以此類推其餘函數定。
THCAR.H也提供了一個TCHAR類型來解決兩個字符數據類型的問題。若是UNICODE標識符被定義了,
typedef wchar_t TCHAR;
不然的話,TCHAR就是char
typedef char TCHAR;
關於寬字符字符串前綴L的解決辦法以下,若是UNICODE被定義了
#define __T(x) L##x
預處理將L和宏參數拼接在一塊兒,例如x是hello,則L##x就是L"hello"
若是UNICODE沒有被定義,則__T宏就定義以下:
#define __T(x) x
而後
#define _T(x) __T(x) #define _TEXT(x) __T(x)
因此寫字符串的時候只須要將字符串字面寫在宏內就能夠了
_TEXT("hello!");
這樣若是UNICODE被定義了,字符串就解釋爲寬字符組成的,若是沒有被定義,就解釋爲8位字符組成的。
###關於char16_t和char32_t
隨着Unicode的發展,類型wchar_t已經不足以知足需求,好比在字符串編碼時,若是有特定的符號和長度特徵的類型將頗有幫助,而wchar_t的符號和長度不一樣的C/C++庫有不一樣的規定。所以C++11新增長了char16_t和char32_t。
char16_t:無符號類型,長16位,char32_t無符號類型,長32位
前綴u和U分別指出字符字面值的類型爲char16_t和char32_t。