C:漢字儲存

PamShao發表於2021-07-20

問題

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、漢字的儲存

2、使用陣列來儲存中文(字串)

3、C語言:GB2312編碼和GBK編碼,將中文儲存到計算機

4、C語言/C++字元編碼方式解析

相關文章