中文編碼轉換是跨平台、跨地區中文應用開發的必經之路。主流內碼包括簡體 GB2312、GBK 及繁體 BIG5。早期靠巨大碼表硬轉,資源消耗大且不完美。Windows API 提供 MultiByteToWideChar 與 WideCharToMultiByte 兩大核心函數,配合 Unicode 作為中介,可高效、準確完成各編碼間互轉,無需外部碼表。
雙階段轉換模型:
MultiByteToWideChar(CodePage, ...)WideCharToMultiByte(CodePage, ...)關鍵代碼頁常量:
936 = GBK (兼容 GB2312)950 = BIG520936 = GB2312 (部分系統支持)54936 = GB180301200 = UTF-1665001 = UTF-8void BIG5_to_GBK(char *buf) {
if (!buf || !*buf) return;
int len = strlen(buf);
wchar_t *wbuf = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
if (!wbuf) return;
// BIG5(950) -> Unicode
int wlen = MultiByteToWideChar(950, 0, buf, len, wbuf, len + 1);
if (wlen == 0) { free(wbuf); return; }
// Unicode -> GBK(936)
BOOL usedDefault = FALSE;
int rlen = WideCharToMultiByte(936, 0, wbuf, wlen, buf, len + 1, "?", &usedDefault);
if (rlen > 0) buf[rlen] = '\0';
free(wbuf);
}
void GBK_to_BIG5(char *buf) {
if (!buf || !*buf) return;
int len = strlen(buf);
wchar_t *wbuf = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
if (!wbuf) return;
// GBK(936) -> Unicode
int wlen = MultiByteToWideChar(936, 0, buf, len, wbuf, len + 1);
if (wlen == 0) { free(wbuf); return; }
// Unicode -> BIG5(950)
BOOL usedDefault = FALSE;
int rlen = WideCharToMultiByte(950, 0, wbuf, wlen, buf, len + 1, "?", &usedDefault);
if (rlen > 0) buf[rlen] = '\0';
free(wbuf);
}
void GB2312_to_GBK(char *buf) {
if (!buf || !*buf) return;
int len = strlen(buf);
// 使用簡體中文排序標識
LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_PRC);
// 先查所需緩衝區大小
int need = LCMapString(lcid, LCMAP_TRADITIONAL_CHINESE, buf, len, NULL, 0);
if (need == 0) return;
char *tmp = (char*)malloc(need + 1);
if (!tmp) return;
LCMapString(lcid, LCMAP_TRADITIONAL_CHINESE, buf, len, tmp, need);
strncpy(buf, tmp, need);
buf[need] = '\0';
free(tmp);
}
void GBK_to_GB2312(char *buf) {
if (!buf || !*buf) return;
int len = strlen(buf);
// 使用 BIG5 排序標識進行簡化轉換
LCID lcid = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_CHINESE_BIG5);
int need = LCMapString(lcid, LCMAP_SIMPLIFIED_CHINESE, buf, len, NULL, 0);
if (need == 0) return;
char *tmp = (char*)malloc(need + 1);
if (!tmp) return;
LCMapString(lcid, LCMAP_SIMPLIFIED_CHINESE, buf, len, tmp, need);
strncpy(buf, tmp, need);
buf[need] = '\0';
free(tmp);
}
無直接 API 時,以 GBK 為中介:
GB2312_to_GBK() → GBK_to_BIG5()BIG5_to_GBK() → GBK_to_GB2312()2 * len + 2 字節緩衝區,或先用 NULL 目標查詢所需大小。GetLastError() 獲取詳細錯誤碼。String.c_str() 作輸入:返回的是 const char*,轉換需可寫緩衝區。iconv、ICU 庫或 C++17 std::wstring_convert (已棄用) / std::from_chars 配合第三方庫。
#include
#include
#include
#include
// 上述四個函數實現...
int main() {
char buf[256] = "中華人民共和國"; // 假設源文件為 GB2312/GBK 編碼保存
printf("原始: %s\n", buf);
// GB2312 -> GBK
strcpy(buf, "中華人民共和國");
GB2312_to_GBK(buf);
printf("GBK: %s\n", buf);
// GB2312 -> BIG5 (經 GBK 中轉)
strcpy(buf, "中華人民共和國");
GB2312_to_GBK(buf);
GBK_to_BIG5(buf);
printf("BIG5: %s\n", buf);
return 0;
}
總結: Windows 平台下,利用 MultiByteToWideChar/WideCharToMultiByte 配合 Unicode 中介,是實現 GB2312/GBK/BIG5 互轉的標準、高效、免碼表方案。掌握代碼頁常量與雙階段轉換模型,即可輕鬆應對中文編碼互轉需求。