Windows API 多使用 Unicode(wchar_t*),而標準庫、網路協定、第三方庫常用 ANSI/UTF-8(char*)。專案中頻繁需要在 std::wstring 與 std::string 之間轉換。本文提供兩個健全的轉換函式,支援指定地區設定(Code Page 936 簡體中文)。
#include <string>
#include <clocale>
#include <cstdlib>
std::wstring ToWideString(const char* pszStr, int len = -1)
{
if (!pszStr) return L"";
if (len < 0) len = (int)strlen(pszStr);
// 設定地區為中文代碼頁 936 (GBK)
std::setlocale(LC_ALL, ".936");
int wlen = MultiByteToWideChar(CP_ACP, 0, pszStr, len, NULL, 0);
if (wlen <= 0) return L"";
std::wstring wstr(wlen, L'\0');
MultiByteToWideChar(CP_ACP, 0, pszStr, len, &wstr[0], wlen);
std::setlocale(LC_ALL, "C"); // 還原
return wstr;
}
std::string ToNarrowString(const wchar_t* pwzStr, int len = -1)
{
if (!pwzStr) return "";
if (len < 0) len = (int)wcslen(pwzStr);
std::setlocale(LC_ALL, ".936");
int nlen = WideCharToMultiByte(CP_ACP, 0, pwzStr, len, NULL, 0, NULL, NULL);
if (nlen <= 0) return "";
std::string str(nlen, '\0');
WideCharToMultiByte(CP_ACP, 0, pwzStr, len, &str[0], nlen, NULL, NULL);
std::setlocale(LC_ALL, "C");
return str;
}
std::string ansi = "中文測試";
std::wstring wide = ToWideString(ansi.c_str());
// wide == L"中文測試"
std::string back = ToNarrowString(wide.c_str());
// back == "中文測試"
若專案統一使用 UTF-8,請將 CP_ACP 改為 CP_UTF8,並移除 setlocale 呼叫:
std::wstring Utf8ToWide(const std::string& utf8) {
int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0);
std::wstring w(wlen, L'\0');
MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, &w[0], wlen);
return w;
}
std::string WideToUtf8(const std::wstring& wide) {
int nlen = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, NULL, 0, NULL, NULL);
std::string s(nlen, '\0');
WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, &s[0], nlen, NULL, NULL);
return s;
}
// ANSI/MBCS 專案
CStringA ansi = "測試";
CStringW wide = ansi; // 隱含轉換 (需 _UNICODE 未定義)
// Unicode 專案
CStringW wide = L"測試";
CStringA ansi = wide; // 隱含轉換
// 手動控制 (ATL 轉換巨集)
USES_CONVERSION;
LPCWSTR w = A2W(ansi);
LPCSTR a = W2A(wide);
setlocale 非執行緒安全;多執行緒環境請改用 MultiByteToWideChar/WideCharToMultiByte 直接指定 CP_ACP 或 CP_UTF8,不要呼叫 setlocale。NULL 取得所需長度,再配置記憶體。