C/C++寬窄字符轉換與輸出的多種實現方法
前言
如果是C/C++程序員,對于VS應該是不陌生的,可謂是C/C++程序手中的利器
但如果稍微深入學習就會發(fā)現,windows API大部分都是分為寬字節(jié)與窄字節(jié)的,比如常見的MessageboxA與MessageBoxW函數,這時候就會出現很多問題,最常見的便是亂碼
需要注意的是,WIndows底層函數均采用的是寬字節(jié),即使你使用的是char,程序真正執(zhí)行的時候,還是會在底層將char轉化為wchar_t,這就意味著使用窄字節(jié)效率是比不上寬字節(jié)的
同時需要知道.wchar_t是支持多個國家語言的,而char只支持本國語言.
一、什么是寬字節(jié)?什么是窄字節(jié)?
認識寬窄字節(jié)最好的辦法就是動手實驗一下

可以看到,最直接的影響就是大小,char只占一個字節(jié),而wchar_t要占兩個字節(jié),并且需要在字符串前加 L 才表示是寬字節(jié)
其實還有很多細節(jié),比如這里是使用的字符c,如果是使用的漢字,還能正常使用嗎?很多問題需要自己碰到并解決,最后才能是自己的東西
二、寬窄字節(jié)之間的轉化方法
1.Windows API進行轉化
頭文件:
#include<Windows.h>
用到的函數
窄字節(jié)轉寬字節(jié):
int MultiByteToWideChar( UINT CodePage, //要轉換的代碼頁,一般直接填CP_ACP,表示當前系統(tǒng)使用的代碼頁 DWORD dwFlags, //轉換標志,直接填0即可 LPCCH lpMultiByteStr, //要轉換的窄字節(jié)字符串 int cbMultiByte, //窄字節(jié)字符串的長度,以字節(jié)計算 LPWSTR lpWideCharStr, //存放轉換完成的寬字符緩沖區(qū) int cchWideChar //存放寬字符緩沖區(qū)的大小 );
寬字節(jié)轉窄字節(jié):
int WideCharToMultiByte( UINT CodePage,//要轉換的代碼頁,一般直接填CP_ACP,表示當前系統(tǒng)使用的代碼頁 DWORD dwFlags,//轉換標志,直接填0即可 LPCWCH lpWideCharStr,//要轉換的寬字節(jié)字符串 int cchWideChar, //寬字節(jié)字符串的長度,以字符計算 LPSTR lpMultiByteStr, //存放轉換完成的窄字符緩沖區(qū) int cbMultiByte, //存放寬字符緩沖區(qū)的大小 LPCCH lpDefaultChar, //如果字符無法轉換,則使用該字符填充,一般填0,默認即可 LPBOOL lpUsedDefaultChar //如果出現無法轉換的字符,該參數被設為true,默認填NULL即可 );
一般寬字符是窄字符字節(jié)長度的兩倍,但也有可能出現意外情況,或者不想自己計算需要多大的緩沖,則可以調用兩次該函數,第一次返回需要的大小,第二次進行轉換
下面是我封裝的兩個函數,可直接使用,但需要自己delete內存,可以自己使用wstring和string進行替換
窄字節(jié)轉寬字節(jié):
//str:要轉換的窄字符串
//len:接受轉換成功后寬字符的長度,可直接填NULL,不接收
wchar_t* AtoW(const char* str, int* len)
{
int wcLen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
wchar_t* newBuf = new wchar_t[wcLen + 1]{};
MultiByteToWideChar(CP_ACP, 0, str, -1, newBuf, wcLen);
if (len != NULL) {
*len = wcLen;
}
return newBuf;
}
寬字節(jié)轉窄字節(jié)
//str:要轉換的寬字符串
//len:接受轉換成功后窄字符的長度,可直接填NULL,不接收
char* WtoA(const wchar_t* str, int* len)
{
int cLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, 0, NULL);
char* newBuf = new char[cLen + 1]{};
WideCharToMultiByte(CP_ACP, 0, str, -1, newBuf, cLen, 0, NULL);
if (len != NULL) {
*len = cLen;
}
return newBuf;
}
2.C/C++庫函數轉換
用到的頭文件:
#include<cstdlib> //包含轉換函數 #include<locale> //包含設置地域函數
用到的函數:
設置地域,當試圖轉換中文時,需要設置,否則為亂碼
char* setlocale( int _Category, //設置該函數影響范圍,一般直接填LC_ALL,即全部影響 char const* _Locale //一般填空,即使用本地地域信息 );
標準窄轉寬:
size_t mbstowcs( wchar_t _Dest, //轉換后存放的地方 const char * _Source, //要轉換的內容 size_t _MaxCount //轉換后存放地方的大小,以字符個數計算 )
使用:
#define _CRT_SECURE_NO_WARNINGS //必須定義宏,否則VS報錯
#include<iostream>
#include<cstdlib>
#include<locale>
using namespace std;
int main() {
setlocale(LC_ALL, ""); //設置本地地域信息.否則轉換中文出現亂碼
wchar_t buf[0xFF];
mbstowcs(buf, "哈哈哈哈", 0xFF);
}
標準寬轉窄:
size_t wcstombs( char*_Dest, //轉換后存放的地方 const wchar_t* _Source, //要轉換的內容 size_t _MaxCount //轉換后存放地方的大小,以字符個數計算 )
使用:
#define _CRT_SECURE_NO_WARNINGS //必須定義宏,否則VS報錯
#include<iostream>
#include<cstdlib>
#include<locale>
using namespace std;
int main(){
setlocale(LC_ALL,""); //設置本地地域信息.否則轉換中文出現亂碼
char buf[0xFF];
wcstombs(buf,L"哈哈哈哈哈",sizeof(buf));
}
安全函數窄轉寬:
errno_t mbstowcs_s(
size_t* _PtNumOfCharConverted, //接收轉換成功的字符個數
wchar_t* _DstBuf, //接受成功轉換的字符
size_t _SizeInWords, //_DesBuf緩沖區(qū)大小,以字符計算
char const* _SrcBuf, //要轉化的字符
size_t _MaxCount //最大要轉化的字符數量
);
使用:
#include<iostream>
#include<cstdlib>
using namespace std;
int main() {
wchar_t buf[0xFF];
mbstowcs_s(NULL,buf,0xFF, "哈哈哈哈", 0xFF);
}
安全函數寬轉窄:
errno_t wcstombs_s(
size_t* _PtNumOfCharConverted, //接收轉換成功的字符個數
wchar_t* _DstBuf, //接受成功轉換的字符
size_t _SizeInWords, //_DesBuf緩沖區(qū)大小,以字符計算
char const* _SrcBuf, //要轉化的字符
size_t _MaxCount //最大要轉化的字符數量
);
使用:
#include<iostream>
#include<cstdlib>
#include<locale>
using namespace std;
int main() {
setlocale(LC_ALL,"");
char buf[0xFF];
wcstombs_s(NULL, buf, 0xFF, L"哈哈哈哈哈", sizeof(buf));
printf("%s",buf);
}
大家可能看到,我有時使用了setlocal,有時沒有使用,這個可以根據具體情況而定,如果出現中文無法轉化的情況,就要考慮使用這個函數了
而且我都沒有接收轉化字符個數,也就是第一個參數,如果需要準確接受轉化成功字符的個數,就必須要使用setlocal函數
可能大家還看到過_wcstombs_s_l等函數,這個函數還需要_create_locale與 _free_locale函數配合使用,考慮下來,過于麻煩,不如上面的幾種轉化方法,所以便不予講解,大家有興趣可以去查看官網說明,鏈接在此 函數說明 設置本地說明
3.ATL庫轉換
ATL模板庫是微軟推出的一個C++模板庫,在visual studio中安裝了C++開發(fā)環(huán)境就可以正常使用
寬轉窄:
#include<iostream>
#include<atlconv.h> //頭文件
using namespace std;
int main() {
USES_CONVERSION; //必須添加
wchar_t buf[] = L"哈哈哈哈哈哈";
char *nbuf=W2A(buf); //使用棧空間進行轉換,不需要delete
cout << nbuf << endl;
}
窄轉寬:
#include<iostream>
#include<locale>
#include<atlconv.h> //頭文件
using namespace std;
int main() {
setlocale(LC_ALL,""); //本地化,為輸出漢字
USES_CONVERSION; //必須添加
char buf[] = "哈哈哈哈哈哈";
wchar_t *nbuf=A2W(buf); //使用棧空間進行轉換,不需要delete
wcout << nbuf;
}
4.COM組件轉換
寬轉窄:
#include<comutil.h>
#pragma comment(lib, "comsuppw.lib")
int main() {
wchar_t str[] = L"哈哈哈";
char *s=_com_util::ConvertBSTRToString(str); //轉換函數
//其它操作
delete[] s; //釋放內存
}
窄轉寬:
#include<comutil.h>
#pragma comment(lib, "comsuppw.lib")
int main() {
char str[] = "哈哈哈哈";
wchar_t *s=_com_util::ConvertStringToBSTR(str); //轉換函數
//其它操作
SysFreeString(s); //釋放內存
}
三.解決VS控制臺無法輸出寬字符問題
方法一:使用setlocal和printf函數:
#include<iostream>
#include<locale>
using namespace std;
int main() {
setlocale(LC_ALL,"");
printf("%ls",L"了解");
}
方法二:使用setlocal與wcout
#include<iostream>
#include<locale>
using namespace std;
int main() {
setlocale(LC_ALL,"");
wcout << L"哈哈哈哈啊";
}
以上兩種方法,如果寬字符串中沒有中文字符,則可不使用setlocal函數
方法三:使用WriteConsoleW函數
#include<Windows.h>
int main() {
wchar_t buf[]=L"哈哈哈哈哈哈哈哈哈哈";
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),buf,sizeof(buf)/2, NULL, 0);
}到此這篇關于C/C++寬窄字符轉換與輸出的多種實現方法的文章就介紹到這了,更多相關C/C++寬窄字符轉換與輸出內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

