Windows 開發中頻繁面臨多字節字符集(MBCS/ANSI)與寬字符(Unicode/WideChar)互轉需求。本文系統梳理四種主流轉換方案:Win32 API 兩對核心函數、ATL 便利宏、C++ 標準庫 codecvt、以及現代 MultiByteToWideChar 封裝最佳實踐。
MultiByteToWideCharint MultiByteToWideChar(
UINT CodePage, // 代碼頁:CP_ACP(系統默認)、CP_UTF8、CP_OEMCP 等
DWORD dwFlags, // 標誌位:MB_PRECOMPOSED、MB_ERR_INVALID_CHARS 等,通常 0
LPCSTR lpMultiByteStr,// 源字符串指針
int cbMultiByte, // 源字節數,-1 表示以 '\0' 結尾自動計算
LPWSTR lpWideCharStr, // 目標緩衝區,NULL 時返回所需字符數
int cchWideChar // 目標緩衝區字符容量
);
// 第一步:獲取所需緩衝區大小
int len = MultiByteToWideChar(CP_ACP, 0, mbStr, -1, NULL, 0);
if (len <= 0) return ERROR;
// 第二步:分配緩衝區並轉換
std::vector<wchar_t> buf(len);
int result = MultiByteToWideChar(CP_ACP, 0, mbStr, -1, buf.data(), len);
// buf[len-1] 為 L'\0',有效字符數為 result-1
WideCharToMultiByteint WideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
LPSTR lpMultiByteStr,
int cbMultiByte,
LPCSTR lpDefaultChar, // 無法轉換時的替換字符,NULL 為 '?'
LPBOOL pfUsedDefaultChar// 是否使用了替換字符
);
int len = WideCharToMultiByte(CP_ACP, 0, wcStr, -1, NULL, 0, NULL, NULL);
if (len <= 0) return ERROR;
std::vector<char> buf(len);
WideCharToMultiByte(CP_ACP, 0, wcStr, -1, buf.data(), len, NULL, NULL);
#include <atlconv.h> // 需包含 ATL 頭文件
USES_CONVERSION; // 每次轉換前必須調用!分配棧緩衝區
wchar_t wszText[] = L"Unicode字符串";
char szText[] = "ANSI字符串";
printf("%s\n", W2A(wszText)); // 寬 → 多
wprintf(L"%s\n", A2W(szText)); // 多 → 寬
CP_ACP建議:僅用於簡單工具、測試代碼、非熱路徑。生產代碼請使用 Win32 API 手動管理堆內存。
<codecvt> 標準庫方案(跨平台、類型安全)#include <codecvt>
#include <locale>
#include <string>
// UTF-8 ↔ UTF-16/32 (wchar_t)
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
std::wstring wide = L"Hello 世界";
std::string utf8 = converter.to_bytes(wide); // 寬 → UTF-8
std::wstring wide2 = converter.from_bytes(utf8); // UTF-8 → 寬
// 注意:C++17 棄用 codecvt,C++20 移除。長期項目請遷移至 ICU 或獨立庫。
class StringConverter {
public:
// 多字節(指定代碼頁) → 寬字符
static std::wstring ToWide(const std::string& mb, UINT cp = CP_UTF8) {
if (mb.empty()) return L"";
int len = MultiByteToWideChar(cp, 0, mb.c_str(), -1, NULL, 0);
if (len <= 0) throw std::runtime_error("MultiByteToWideChar failed");
std::wstring ws(len - 1, L'\0'); // -1 排除結束符
MultiByteToWideChar(cp, 0, mb.c_str(), -1, &ws[0], len);
return ws;
}
// 寬字符 → 多字節(指定代碼頁)
static std::string ToMultiByte(const std::wstring& ws, UINT cp = CP_UTF8) {
if (ws.empty()) return "";
int len = WideCharToMultiByte(cp, 0, ws.c_str(), -1, NULL, 0, NULL, NULL);
if (len <= 0) throw std::runtime_error("WideCharToMultiByte failed");
std::string mb(len - 1, '\0');
WideCharToMultiByte(cp, 0, ws.c_str(), -1, &mb[0], len, NULL, NULL);
return mb;
}
// 常用別名
static std::wstring AnsiToWide(const std::string& s) { return ToWide(s, CP_ACP); }
static std::string WideToAnsi(const std::wstring& s) { return ToMultiByte(s, CP_ACP); }
static std::wstring Utf8ToWide(const std::string& s) { return ToWide(s, CP_UTF8); }
static std::string WideToUtf8(const std::wstring& s) { return ToMultiByte(s, CP_UTF8); }
};
| 常量 | 含義 | 適用場景 |
|---|---|---|
CP_ACP | 系統默認 ANSI 代碼頁 | 本地化應用、舊系統交互 |
CP_UTF8 | UTF-8 | 跨平台、網絡傳輸、現代應用首選 |
CP_OEMCP | OEM 代碼頁 (如中文 CP936) | 控制台程序、舊 DOS 應用 |
1200 | UTF-16LE | Windows 內部寬字符 |
1201 | UTF-16BE | 網絡序寬字符 |
-1;調用時傳完整長度<= 0,調用 GetLastError() 獲取具體錯誤碼'\0' 結尾,或顯式傳遞長度wchar_t,長度計算需注意本文出自 “平凡的日子” 博客,轉載請保留出處:原文鏈接