C語言 使用char字符實現漢字處理


  • 系統:windows 64
  • 編譯器:gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project)
  • 文本編輯器:notepad
  • 控制台:Cmder
  • 編程語言:C、Python

  首先,要想打印漢字,必須考慮到編碼問題。在windows下,由於系統使用GBK編碼,而GCC解析時使用UTF-8而會導致以下代碼運行時出現亂碼:

#include <stdio.h>

int main()
{
    char *str = "你好,世界!";

    printf("%s\n", str);

    return 0;
}

 

 

 

  解決方法為:使用“-fexec-charset=gbk”命令

 

  解決了編碼問題,我們還需要了解幾點:

  • char類型本質上是數字,占據一個字節(即八位),可以通過%d打印編碼,通過%c打印字符
  • 在C語言中,一個漢字占據兩個char類型
  • 漢字的兩個char類型為負數
  • 在打印漢字時,它的兩個char必須緊跟着

  根據這幾點,我們可以打印出漢字以及它們的編碼:

#include <stdio.h>
#include <string.h>

int main()
{
    // str為字符指針,指向一個字符字面量,這個字符字面量由'\0'結尾
    char *str = "你好,世界!Hello, world!";
    // chr為字符指針,指向str所指向的字符字面量的第一個字符的地址,即'你'字符的兩個char中的第一個
    char *chr = str;

    printf("%zu %s\n", strlen(str), str);
    // 如果遇到'\0',說明字符串結束了
    while (*chr != '\0')
    {
        // 如果chr的編碼為負數,則說明遇到了一個漢字
        if (*chr < 0)
        {
            // 打印漢字及漢字的編碼
            // 注意兩個char必須緊緊跟着打印(%c%c),否則會打印出 ?? 
            printf("%c%c: %d%d\n", *chr, *(chr+1), *(chr), *(chr+1));
            // chr自增兩個字節(因為每個漢字都由兩個char組成)
            chr += 2;
        }
        else
        {
            // 打印英文字符
            printf("%c: %d\n", *chr, *chr);
            // chr自增一個字節
            ++chr;
        }
    }

    return 0;
}

  從上圖,我們可以看出,這個字符串占據了25個字節,4個漢字加2個全角符號占據了12個字節,再加上23個英文字符,總共25個字節。我們可以從下圖更清晰地看出str的構造:

  但是,根據我們在網上查詢的結果,漢字‘你’的GBK編碼應為:C4E3,但是在這里,卻打印出了:-60-29,這是為什么呢?

  這里涉及到進制的問題,可能-60-29是十六進制數C4E3的十進制數?

  首先,我們先通過Python看看C4E3的二進制數以及十進制數。這好像跟-60-29根本不沾邊。

  我們先看看下面的代碼,導入<limits.h>頭文件,看看char類型的取值范圍為多少:

#include <stdio.h>
#include <limits.h>

int main()
{
    printf("[%d ~ %d]\n", CHAR_MIN, CHAR_MAX);
    printf("%c%c\n", 0xC4, 0xE3);return 0;
}

  我們可以看到:char類型的取值范圍為[-128 ~ 127],但是我們卻可以打印出漢字”你“。這是為什么呢?明明char的取值范圍最多127,而漢字“你”的兩個字符分別為:196和227,都超過了這個值。其實這是因為,C語言將這兩個數字的二進制數作為負數處理。C中的char類型有1個字節,占8位,而它的最高位為符號位,當它為0時為正,1時則為負。C通過對正數做補碼操作得到負數。補碼,即對一個二進制數取反,然后再加1。比如,0xC4的二進制數為0b11000100,我們可以看到最高位1,在C中這個數就是負數。我們可以通過對這個二進制數做補碼操作,得到0b00111100,即60。所以0b11000100在C中表示為-60。

   從以上,我們可以發現,GBK編碼中,一個漢字占兩字節。因為C中char類型只占一個字節,所以需要使用兩個char類型來表示漢字。因為C中char為有符號類型,char的表示范圍為[-128 ~ 127],所以在遇到大於127的數字時,會被char表示為負數。

  其實,我們還可以使用unsigned char來實現。char默認是有符號的,取值范圍為:-128 ~127。而unsigned char的取值范圍則為:0~255,那么漢字“你”的編碼就會被顯示為:196和227。

#include <stdio.h>
#include <string.h>

int main()
{
    // str為字符指針,指向一個字符字面量,這個字符字面量由'\0'結尾
    unsigned char *str = (unsigned char *)"你好,世界!Hello, world!";
    // chr為字符指針,指向str所指向的字符字面量的第一個字符的地址,即'你'字符的兩個char中的第一個
    unsigned char *chr = str;

    printf("%zu %s\n", strlen(str), str);
    // 如果遇到'\0',說明字符串結束了
    while (*chr != '\0')
    {
        // 如果chr的編碼大於127,則說明遇到了一個漢字
        if (*chr > 127)
        {
            // 打印漢字及漢字的編碼
            // 注意兩個char必須緊緊跟着打印(%c%c),否則會打印出 ?? 
            printf("%c%c: %d %d\n", *chr, *(chr+1), *(chr), *(chr+1));
            // chr自增兩個字節(因為每個漢字都由兩個char組成)
            chr += 2;
        }
        else
        {
            // 打印英文字符
            printf("%c: %d\n", *chr, *chr);
            // chr自增一個字節
            ++chr;
        }
    }

    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM