定義字符數組 szHello ,初值為 "Hello"。編寫程序1:
#include<stdio.h>#include<string.h>#include<stdlib.h>
int main(int argc, char* argv[]){ char szHello[] = "Hello"; printf("%s\r\n", szHello); system("pause"); return 0;}按 F10 進行單步調試,發現 Hello 字符串的每個字符在內存中各佔一個字節,這就是 ascii碼 。由美國人發明,所以只出現大小寫英文字母、數字和一些符號。因此,最早只有127個字符被編碼到計算機裡,也就是 7位 2進位數字,最高位(第八位)為 0 。
這個編碼表被稱為 ascii編碼,比如大寫字母 H 的編碼是 72(16進位48),小寫字母 o 的編碼是 111(16進位6F)。
定義字符數組 szHello ,初值為 "Hello同學們"。編寫程序2:
#include<stdio.h>#include<string.h>#include<stdlib.h>
int main(int argc, char* argv[]){ char szHello[] = "Hello同學們"; printf("%s\r\n", szHello); system("pause"); return 0;}按 F10 進行單步調試,發現字符串 "Hello" 的每個字符在內存中仍各佔一個字節,但是字符串 "同學們",每一個漢子在內存中卻佔兩個字節。
這是因為,在中國1990年出版的《辭海》就高達14872個漢字,上面提到的 ascii編碼,每個字只用一個字節表示,最多可表示 256 個字,顯然是遠遠不夠的,至少需要兩個字節,而且還不能和ASCII編碼衝突,所以,中國制定了GB2312編碼,用來把中文編進去。
可以想得到的是,全世界有上百種語言,日本,韓國等,並且各國有各國的標準,就會不可避免地出現衝突,結果就是,在多語言混合的文本中,顯示出來會有亂碼。
因此,unicode編碼應運而生。unicode編碼在內存中佔兩個字節,最多可表示 65535 個字,可以把所有語言都統一到一套編碼裡,這樣就解決了亂碼問題。
通過調試結果也可以看出,字節值為正數,用 ascii 編碼表示英文;字節值負數,用 unicode 編碼表示中文。
編譯執行,並不會出現亂碼輸出。
但是如果在英文中文混用的情況下,編譯器判斷一個字節出錯時,會連續判斷錯誤,造成大面積的亂碼。例如將 6F 改為 8F,如下圖所示,導致"同學們"字符串均發生亂碼。
因為中英文混用時,內存中一會佔一個字節,一會佔兩個字節,編譯器處理的難度會提升很多,容易造成亂碼現象。利用空間換時間的思維,不論英文還是中文,都利用 unicode編碼方式,全部在內存空間中佔兩個字節。
將內存空間佔一個字節的變量類型 char ,改為內存空間佔兩個字節的變量類型 unsigned short int 。編寫程序3:
#include<stdio.h>#include<string.h>#include<stdlib.h>
int main(int argc, char* argv[]){ unsigned short int szHello[] = "Hello同學們"; printf("%s\r\n", szHello); system("pause"); return 0;}
因為字符串 "Hello同學們" 仍是 ascii編碼方式,所以編譯未通過,提示無法從 char [12] 轉換為 unsigned short [],沒有可以進行這種轉換的環境。
在字符串前加 L ,如 L"我的字符串" 表示將 ascii編碼字符串轉換成 unicode編碼的字符串。在字符串 "Hello同學們" 前加 L,編寫程序4:
#include<stdio.h>#include<string.h>#include<stdlib.h>
int main(int argc, char* argv[]){ unsigned short int szHello[] = L"Hello同學們"; printf("%s\r\n", szHello); system("pause"); return 0;}編譯通過。按 F10 進行單步調試,字符串中的每個字符和漢字都各佔兩個字節的內存空間。
printf 函數是按 ascii編碼方式列印,默認字符串 \0 結尾,因為字符串 "Hello同學們" 是 unicode編碼,所以在 H 字符後是 00 ,printf 看見 00 結束列印,只輸出 H 。
查看 MSDN 可知,列印 unicode編碼字符串,必須要用 wprintf 函數。因為 wprintf函數是 printf函數的寬字節版本,但兩函數的行為相同。
將 printf 函數改為 wprintf 函數。編寫程序5:
#include<stdio.h>#include<string.h>#include<stdlib.h>
int main(int argc, char* argv[]){ unsigned short int szHello[] = L"Hello同學們"; wprintf(L"%s", szHello); system("pause"); return 0;}編譯執行,只輸出了 Hello,而中文部分字符串"同學們"卻沒有輸出。
只有利用 setlocale 函數,設置當前位置,才能顯示中文部分的字符串。查看 MSDN,輸出簡體中文用 "chs" 。
根據 MSDN 獲取到的修改方式,編寫程序6:
#include<stdio.h>#include<string.h>#include<stdlib.h>#include <locale.h>
int main(int argc, char* argv[]){ setlocale(LC_ALL, "chs"); unsigned short int szHello[] = L"Hello同學們"; wprintf(L"%s\r\n", szHello); system("pause"); return 0;}編譯執行,輸出 "Hello同學們" 成功。
利用編譯選項宏實現 ascii編碼方式和unicode編碼方式的隨時切換,思路為如果定義宏 MYUNICODE ,代碼全部為 unicode編碼模式,否則代碼全部為 ascii編碼模式。編寫程序7:
#include<stdio.h>#include<string.h>#include<stdlib.h>#include <locale.h>
#define MYUNICODE
#ifdef MYUNICODE#define TCHAR unsigned short int#define _tprintf wprintf#define _tmain wmain#define _tsetlocale _wsetlocale#define _tsystem _wsystem#define _T(x) L ## x
#else #define TCHAR char #define _tprintf printf#define _tmain main#define _tsetlocale setlocale#define _tsystem system#define _T(x) x
#endif
int main(int argc, char* argv[]){ _tsetlocale(LC_ALL, _T("chs")); TCHAR szHello[] = _T("Hello同學們"); _tprintf(_T("%s\r\n"), szHello); _tsystem(_T("pause")); return 0;}按 F10 進行單步調試,字符串以 unicode編碼方式在內存中存儲。
注釋掉宏 MYUNICODE 。編寫程序8:
#include<stdio.h>#include<string.h>#include<stdlib.h>#include <locale.h>
#ifdef MYUNICODE#define TCHAR unsigned short int#define _tprintf wprintf#define _tmain wmain#define _tsetlocale _wsetlocale#define _tsystem _wsystem#define _T(x) L ## x
#else #define TCHAR char #define _tprintf printf#define _tmain main#define _tsetlocale setlocale#define _tsystem system#define _T(x) x
#endif
int main(int argc, char* argv[]){ _tsetlocale(LC_ALL, _T("chs")); TCHAR szHello[] = _T("Hello同學們"); _tprintf(_T("%s\r\n"), szHello); _tsystem(_T("pause")); return 0;}按 F10 進行單步調試,字符串以 ascii編碼方式在內存中存儲。