首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

UTF-8 與 GB2312 編碼互轉完整實作 (VC++ WinAPI)

     編輯:關於VC++

背景與問題

Java 預設 UTF-8,VC++ 預設 GB2312,XML 通訊雙端編碼不一致導致中文亂碼。核心解法:UTF-8 ↔ Unicode ↔ GB2312 雙向轉換,利用 WinAPI WideCharToMultiByte / MultiByteToWideChar。

核心 WinAPI 函式


// 寬字元 → 多位元組 (Unicode → ANSI/GB2312/UTF-8)
int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr,
    int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte,
    LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);

// 多位元組 → 寬字元 (ANSI/GB2312/UTF-8 → Unicode)
int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
    int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
  • CP_ACP:系統預設 ANSI 碼頁(中文環境為 GB2312/CP936)。
  • CP_UTF8:UTF-8 碼頁(WinAPI 直接支援)。

輔助工具函式


// 16進位字元 → 4位元二進位字串
CString HexToBin(CString s) { /* switch 表查 '0'~'f' → "0000"~"1111" */ }

// 4位元二進位字串 → 16進位字元
CString BinToHex(CString s) { /* 反向查表 */ }

// 8位元二進位字串 → 整數
int BinToInt(CString s) { /* 位權加總 */ }

UTF-8 → GB2312 轉換流程


WCHAR* UTF_8ToUnicode(char* utf8Ptr) {
    // 取 UTF-8 三位元組
    BYTE b1 = utf8Ptr[0], b2 = utf8Ptr[1], b3 = utf8Ptr[2];
    // 解析位元模式:1110xxxx 10yyyyyy 10zzzzzz → Unicode: xxxxyyyy yyzzzzzz
    CString bin = HexToBin(b1).Right(4) + HexToBin(b2).Right(6) + HexToBin(b3).Right(6);
    // 取高低位元組
    int hi = BinToInt(bin.Left(8));
    int lo = BinToInt(bin.Right(8));
    WCHAR wch = (hi << 8) | lo;
    return &wch; // 注意:實際需動態配置記憶體
}

char* UnicodeToGB2312(WCHAR wch) {
    char* buf = new char[2];
    WideCharToMultiByte(CP_ACP, 0, &wch, 1, buf, 2, NULL, NULL);
    return buf;
}

GB2312 → UTF-8 轉換流程


WCHAR* GB2312ToUnicode(char* gbPtr) {
    WCHAR* wch = new WCHAR;
    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, gbPtr, 2, wch, 1);
    return wch;
}

char* UnicodeToUTF_8(WCHAR wch) {
    // Unicode 16-bit → UTF-8 三位元組編碼
    int hi = wch >> 8, lo = wch & 0xFF;
    CString bin = HexToBin(hi).Right(8) + HexToBin(lo).Right(8); // 16 位元
    // 切分:xxxxyyyy yyzzzzzz → 1110xxxx 10yyyyyy 10zzzzzz
    CString utf8bin = "1110" + bin.Mid(0,4) + "10" + bin.Mid(4,6) + "10" + bin.Mid(10,6);
    char* buf = new char[3];
    buf[0] = BinToInt(utf8bin.Left(8));
    buf[1] = BinToInt(utf8bin.Mid(8,8));
    buf[2] = BinToInt(utf8bin.Right(8));
    return buf;
}

完整字串轉換介面


char* TranslateToUTF_8(char* gbStr, int len) {
    char* out = new char[len * 3 + 1]; // 最坏情况每中文字符变3字节
    int inPos = 0, outPos = 0;
    while (inPos < len) {
        if ((BYTE)gbStr[inPos] < 0x80) { // ASCII 直接複製
            out[outPos++] = gbStr[inPos++];
        } else { // 中文字符:2 bytes GB2312 → 3 bytes UTF-8
            WCHAR* w = GB2312ToUnicode(gbStr + inPos);
            char* u = UnicodeToUTF_8(*w);
            memcpy(out + outPos, u, 3);
            outPos += 3; inPos += 2;
            delete w; delete[] u;
        }
    }
    out[outPos] = '\0';
    return out;
}

現代化改進建議

  • 優先使用 MultiByteToWideChar(CP_UTF8, ...) 直接處理 UTF-8,避免手工位元操作。
  • C++11 std::wstring_convert / std::codecvt_utf8(C++17 棄用)或第三方庫(ICU、utf8cpp)更健壯。
  • 專案全域統一使用 UTF-8(原始碼儲存、網路傳輸、檔案存儲),僅在 Windows API 呼叫邊界轉換。

總結

掌握 UTF-8 ↔ Unicode ↔ GB2312 轉換鏈路與 WinAPI 正確參數,可解決跨平台中文編碼互通難題。建議新專案全面採用 UTF-8 統一編碼,減少轉換層複雜度。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved