問題
C語言中漢字如何儲存?梳理思路!
答案
在計算機中,一個英文字元佔1個位元組,漢字佔兩個位元組,如果用char字元陣列儲存字元時,需要在最後面自動加上一個位元組的結束符“\0”
漢字轉進位制輸出
比如:
//英文字元,佔4個位元組 char Info[] = "abc"; printf("%s\n",Info); printf("Info長度:%d\n",sizeof(Info)); //中文,佔5個位元組 char Han[]="中國"; printf("%s\n",Han); printf("Han長度:%d\n",sizeof(Han));
不同的編碼方式,漢字儲存的位元組數量不同,比如:
GB2312編碼:一個漢字兩個位元組
UTF-8編碼: 一個漢字三個位元組
GBK編碼:一個漢字兩個位元組
UTF-16:一個漢字3個位元組
GB2312 --> GBK --> GB18030 是中文編碼的三套方案,出現的時間從早到晚,收錄的字元數目依次增加,並且向下相容。GB2312 和 GBK 收錄的字元數目較少,用 1~2個位元組儲存;GB18030 收錄的字元最多,用1、2、4 個位元組儲存。
1) 從整體上講,GB2312 和 GBK 的編碼方式一致,具體為:
- 對於 ASCII 字元,使用一個位元組儲存,並且該位元組的最高位是 0,這和 ASCII 編碼是一致的,所以說 GB2312 完全相容 ASCII。
- 對於中國的字元,使用兩個位元組儲存,並且規定每個位元組的最高位都是 1。
例如對於字母A
,它在記憶體中儲存為 01000001;對於漢字中
,它在記憶體中儲存為 11010110 11010000。由於單位元組和雙位元組的最高位不一樣,所以字元處理軟體很容易區分一個字元到底用了幾個位元組。
2) GB18030 為了容納更多的字元,並且要區分兩個位元組和四個位元組,所以修改了編碼方案,具體為:
- 對於 ASCII 字元,使用一個位元組儲存,並且該位元組的最高位是 0,這和 ASCII、GB2312、GBK 編碼是一致的。
- 對於常用的中文字元,使用兩個位元組儲存,並且規定第一個位元組的最高位是 1,第二個位元組的高位最多隻能有一個連續的 0(第二個位元組的最高位可以是 1 也可以是 0,但是當它是 0 時,次高位就不能是 0 了)。注意對比 GB2312 和 GBK,它們要求兩個位元組的最高位為都必須為 1。
- 對於罕見的字元,使用四個位元組儲存,並且規定第一個和第三個位元組的最高位是 1,第二個和第四個位元組的高位必須有兩個連續的 0。
例如對於字母A
,它在記憶體中儲存為 01000001;對於漢字中
,它在記憶體中儲存為 11010110 11010000;對於藏文གྱུ
,它在記憶體中的儲存為 10000001 00110010 11101111 00110000。
字元處理軟體在處理文字時,從左往右依次掃描每個位元組:
- 如果遇到的位元組的最高位是 0,那麼就會斷定該字元只佔用了一個位元組;
- 如果遇到的位元組的最高位是 1,那麼該字元可能佔用了兩個位元組,也可能佔用了四個位元組,不能妄下斷論,所以還要繼續往後掃描:
- 如果第二個位元組的高位有兩個連續的 0,那麼就會斷定該字元佔用了四個位元組;
- 如果第二個位元組的高位沒有連續的 0,那麼就會斷定該字元佔用了兩個位元組。
可見,當字元佔用兩個或者四個位元組時,GB18030 編碼要檢測兩次,處理效率比 GB2312 和 GBK 都低。
GBK 於 1995 年釋出,這一年也是網際網路爆發的元年,國人使用電腦越來越多,也許是 GBK 這頭豬正好站在風口上,它就飛起來了,後來的中文版 Windows 都將 GBK 作為預設的中文編碼方案。
注意,這裡我說 GBK 是預設的中文編碼方案,並沒有說 Windows 預設支援 GBK。Windows 在核心層面使用的是 Unicode 字符集(嚴格來說是 UTF-16 編碼),但是它也給使用者留出了選擇的餘地,如果使用者不希望使用 Unicode,而是希望使用中文編碼方案,那麼這個時候 Windows 預設使用 GBK(當然,你可以選擇使用 GB2312 或者 GB18030,不過一般沒有這個必要)。
漢字編碼輸出
漢字編碼並輸出示例:
//漢字編碼 unsigned char Han[]="中國"; printf("漢字:%s\n",Han); printf("十六進位制:"); for(int i=0;i<4;i++) { printf("%X",Han[i]); } printf("\n十進位制:"); for(int i=0;i<4;i++) { printf("%d",Han[i]); }
漢字編碼輸出儲存
漢字編碼儲存示例:
//漢字編碼儲存 unsigned char Han[] = "中國"; FILE* fp = fopen("out.txt", "w");//輸出 printf("漢字:%s\n", Han); fputs("十六進位制:", fp); for (int i = 0; i < 4; i++) { fprintf(fp, "%X", Han[i]); } fseek(fp, 0, SEEK_END); fputs("\n十進位制:", fp); for (int i = 0; i < 4; i++) { fprintf(fp, "%d", Han[i]); } fclose(fp);
參考
1、漢字的儲存