本来以为转码只能用第三方库或者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;
}