本來以爲轉碼只能用第三方庫或者API的,沒想到標準庫也帶了轉碼的函數
C語言
用到wcstombs、mbstowcs,編碼要用setlocale設置,不過CRT增強版的_wcstombs_l和_mbstowcs_l可以設置局部的locale
#include <locale.h>
#include <stdlib.h>
char* W2A(wchar_t* src)
{
_locale_t lc = _create_locale(LC_CTYPE, ""); // 使用系統設置的locale
size_t size = 0;
_wcstombs_s_l(&size, NULL, 0, src, _TRUNCATE, lc); // 獲取緩衝size
char* dst = (char*)malloc(size);
_wcstombs_s_l(&size, dst, size, src, _TRUNCATE, lc);
_free_locale(lc);
return dst;
}
wchar_t* A2W(char* src)
{
_locale_t lc = _create_locale(LC_CTYPE, ""); // 使用系統設置的locale
size_t size = 0;
_mbstowcs_s_l(&size, NULL, 0, src, _TRUNCATE, lc); // 獲取緩衝size
wchar_t* dst = (wchar_t*)malloc(size * sizeof(wchar_t));
_mbstowcs_s_l(&size, dst, size, src, _TRUNCATE, lc);
_free_locale(lc);
return dst;
}
C++
用到C++11的wstring_convert的to_bytes和from_bytes,編碼還是看locale
#include <locale>
#include <codecvt>
std::string W2A(const std::wstring& src)
{
typedef std::codecvt<wchar_t, char, mbstate_t> cvttype;
std::locale lc(""); // 使用系統設置的locale
auto& cvt = std::use_facet<cvttype>(lc);
std::wstring_convert<cvttype> cv(&cvt);
return cv.to_bytes(src);
}
std::wstring A2W(const std::string& src)
{
typedef std::codecvt<wchar_t, char, mbstate_t> cvttype;
std::locale lc(""); // 使用系統設置的locale
auto& cvt = std::use_facet<cvttype>(lc);
std::wstring_convert<cvttype> cv(&cvt);
return cv.from_bytes(src);
}
順帶一提如果要改變輸出流的編碼只需要調用imbue,還有codecvt頭文件自帶了各種Unicode編碼轉UTF-8的codecvt
#include <locale>
#include <codecvt>
// ...
std::wofstream f(L"這是UTF-8文件.txt");
f.imbue(std::locale(std::locale(), new std::codecvt_utf8_utf16<wchar_t>));
f << L"這是UTF-16" << std::endl;
Windows API
這個知道的人就多了,用到WideCharToMultiByte和MultiByteToWideChar,可以設置代碼頁
#include <Windows.h>
char* W2A(wchar_t* src)
{
int srcSize = (int)wcslen(src);
int size = WideCharToMultiByte(CP_THREAD_ACP, 0, src, srcSize, NULL, 0, NULL, NULL);
char* dst = (char*)malloc(size + 1);
WideCharToMultiByte(CP_THREAD_ACP, 0, src, srcSize, dst, size + 1, NULL, NULL);
dst[size] = '\0';
return dst;
}
wchar_t* A2W(char* src)
{
int srcSize = (int)strlen(src);
int size = MultiByteToWideChar(CP_THREAD_ACP, 0, src, srcSize, NULL, 0);
wchar_t* dst = (wchar_t*)malloc((size + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_THREAD_ACP, 0, src, srcSize, dst, size + 1);
dst[size] = L'\0';
return dst;
}