C/C++寬窄字符轉(zhuǎn)換與輸出的多種實(shí)現(xiàn)方法
前言
如果是C/C++程序員,對(duì)于VS應(yīng)該是不陌生的,可謂是C/C++程序手中的利器
但如果稍微深入學(xué)習(xí)就會(huì)發(fā)現(xiàn),windows API大部分都是分為寬字節(jié)與窄字節(jié)的,比如常見(jiàn)的MessageboxA與MessageBoxW函數(shù),這時(shí)候就會(huì)出現(xiàn)很多問(wèn)題,最常見(jiàn)的便是亂碼
需要注意的是,WIndows底層函數(shù)均采用的是寬字節(jié),即使你使用的是char,程序真正執(zhí)行的時(shí)候,還是會(huì)在底層將char轉(zhuǎn)化為wchar_t,這就意味著使用窄字節(jié)效率是比不上寬字節(jié)的
同時(shí)需要知道.wchar_t是支持多個(gè)國(guó)家語(yǔ)言的,而char只支持本國(guó)語(yǔ)言.
一、什么是寬字節(jié)?什么是窄字節(jié)?
認(rèn)識(shí)寬窄字節(jié)最好的辦法就是動(dòng)手實(shí)驗(yàn)一下
可以看到,最直接的影響就是大小,char只占一個(gè)字節(jié),而wchar_t要占兩個(gè)字節(jié),并且需要在字符串前加 L 才表示是寬字節(jié)
其實(shí)還有很多細(xì)節(jié),比如這里是使用的字符c,如果是使用的漢字,還能正常使用嗎?很多問(wèn)題需要自己碰到并解決,最后才能是自己的東西
二、寬窄字節(jié)之間的轉(zhuǎn)化方法
1.Windows API進(jìn)行轉(zhuǎn)化
頭文件:
#include<Windows.h>
用到的函數(shù)
窄字節(jié)轉(zhuǎn)寬字節(jié):
int MultiByteToWideChar( UINT CodePage, //要轉(zhuǎn)換的代碼頁(yè),一般直接填CP_ACP,表示當(dāng)前系統(tǒng)使用的代碼頁(yè) DWORD dwFlags, //轉(zhuǎn)換標(biāo)志,直接填0即可 LPCCH lpMultiByteStr, //要轉(zhuǎn)換的窄字節(jié)字符串 int cbMultiByte, //窄字節(jié)字符串的長(zhǎng)度,以字節(jié)計(jì)算 LPWSTR lpWideCharStr, //存放轉(zhuǎn)換完成的寬字符緩沖區(qū) int cchWideChar //存放寬字符緩沖區(qū)的大小 );
寬字節(jié)轉(zhuǎn)窄字節(jié):
int WideCharToMultiByte( UINT CodePage,//要轉(zhuǎn)換的代碼頁(yè),一般直接填CP_ACP,表示當(dāng)前系統(tǒng)使用的代碼頁(yè) DWORD dwFlags,//轉(zhuǎn)換標(biāo)志,直接填0即可 LPCWCH lpWideCharStr,//要轉(zhuǎn)換的寬字節(jié)字符串 int cchWideChar, //寬字節(jié)字符串的長(zhǎng)度,以字符計(jì)算 LPSTR lpMultiByteStr, //存放轉(zhuǎn)換完成的窄字符緩沖區(qū) int cbMultiByte, //存放寬字符緩沖區(qū)的大小 LPCCH lpDefaultChar, //如果字符無(wú)法轉(zhuǎn)換,則使用該字符填充,一般填0,默認(rèn)即可 LPBOOL lpUsedDefaultChar //如果出現(xiàn)無(wú)法轉(zhuǎn)換的字符,該參數(shù)被設(shè)為true,默認(rèn)填NULL即可 );
一般寬字符是窄字符字節(jié)長(zhǎng)度的兩倍,但也有可能出現(xiàn)意外情況,或者不想自己計(jì)算需要多大的緩沖,則可以調(diào)用兩次該函數(shù),第一次返回需要的大小,第二次進(jìn)行轉(zhuǎn)換
下面是我封裝的兩個(gè)函數(shù),可直接使用,但需要自己delete內(nèi)存,可以自己使用wstring和string進(jìn)行替換
窄字節(jié)轉(zhuǎn)寬字節(jié):
//str:要轉(zhuǎn)換的窄字符串 //len:接受轉(zhuǎn)換成功后寬字符的長(zhǎng)度,可直接填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é)轉(zhuǎn)窄字節(jié)
//str:要轉(zhuǎn)換的寬字符串 //len:接受轉(zhuǎn)換成功后窄字符的長(zhǎng)度,可直接填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++庫(kù)函數(shù)轉(zhuǎn)換
用到的頭文件:
#include<cstdlib> //包含轉(zhuǎn)換函數(shù) #include<locale> //包含設(shè)置地域函數(shù)
用到的函數(shù):
設(shè)置地域,當(dāng)試圖轉(zhuǎn)換中文時(shí),需要設(shè)置,否則為亂碼
char* setlocale( int _Category, //設(shè)置該函數(shù)影響范圍,一般直接填LC_ALL,即全部影響 char const* _Locale //一般填空,即使用本地地域信息 );
標(biāo)準(zhǔn)窄轉(zhuǎn)寬:
size_t mbstowcs( wchar_t _Dest, //轉(zhuǎn)換后存放的地方 const char * _Source, //要轉(zhuǎn)換的內(nèi)容 size_t _MaxCount //轉(zhuǎn)換后存放地方的大小,以字符個(gè)數(shù)計(jì)算 )
使用:
#define _CRT_SECURE_NO_WARNINGS //必須定義宏,否則VS報(bào)錯(cuò) #include<iostream> #include<cstdlib> #include<locale> using namespace std; int main() { setlocale(LC_ALL, ""); //設(shè)置本地地域信息.否則轉(zhuǎn)換中文出現(xiàn)亂碼 wchar_t buf[0xFF]; mbstowcs(buf, "哈哈哈哈", 0xFF); }
標(biāo)準(zhǔn)寬轉(zhuǎn)窄:
size_t wcstombs( char*_Dest, //轉(zhuǎn)換后存放的地方 const wchar_t* _Source, //要轉(zhuǎn)換的內(nèi)容 size_t _MaxCount //轉(zhuǎn)換后存放地方的大小,以字符個(gè)數(shù)計(jì)算 )
使用:
#define _CRT_SECURE_NO_WARNINGS //必須定義宏,否則VS報(bào)錯(cuò) #include<iostream> #include<cstdlib> #include<locale> using namespace std; int main(){ setlocale(LC_ALL,""); //設(shè)置本地地域信息.否則轉(zhuǎn)換中文出現(xiàn)亂碼 char buf[0xFF]; wcstombs(buf,L"哈哈哈哈哈",sizeof(buf)); }
安全函數(shù)窄轉(zhuǎn)寬:
errno_t mbstowcs_s( size_t* _PtNumOfCharConverted, //接收轉(zhuǎn)換成功的字符個(gè)數(shù) wchar_t* _DstBuf, //接受成功轉(zhuǎn)換的字符 size_t _SizeInWords, //_DesBuf緩沖區(qū)大小,以字符計(jì)算 char const* _SrcBuf, //要轉(zhuǎn)化的字符 size_t _MaxCount //最大要轉(zhuǎn)化的字符數(shù)量 );
使用:
#include<iostream> #include<cstdlib> using namespace std; int main() { wchar_t buf[0xFF]; mbstowcs_s(NULL,buf,0xFF, "哈哈哈哈", 0xFF); }
安全函數(shù)寬轉(zhuǎn)窄:
errno_t wcstombs_s( size_t* _PtNumOfCharConverted, //接收轉(zhuǎn)換成功的字符個(gè)數(shù) wchar_t* _DstBuf, //接受成功轉(zhuǎn)換的字符 size_t _SizeInWords, //_DesBuf緩沖區(qū)大小,以字符計(jì)算 char const* _SrcBuf, //要轉(zhuǎn)化的字符 size_t _MaxCount //最大要轉(zhuǎn)化的字符數(shù)量 );
使用:
#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); }
大家可能看到,我有時(shí)使用了setlocal,有時(shí)沒(méi)有使用,這個(gè)可以根據(jù)具體情況而定,如果出現(xiàn)中文無(wú)法轉(zhuǎn)化的情況,就要考慮使用這個(gè)函數(shù)了
而且我都沒(méi)有接收轉(zhuǎn)化字符個(gè)數(shù),也就是第一個(gè)參數(shù),如果需要準(zhǔn)確接受轉(zhuǎn)化成功字符的個(gè)數(shù),就必須要使用setlocal函數(shù)
可能大家還看到過(guò)_wcstombs_s_l等函數(shù),這個(gè)函數(shù)還需要_create_locale與 _free_locale函數(shù)配合使用,考慮下來(lái),過(guò)于麻煩,不如上面的幾種轉(zhuǎn)化方法,所以便不予講解,大家有興趣可以去查看官網(wǎng)說(shuō)明,鏈接在此 函數(shù)說(shuō)明 設(shè)置本地說(shuō)明
3.ATL庫(kù)轉(zhuǎn)換
ATL模板庫(kù)是微軟推出的一個(gè)C++模板庫(kù),在visual studio中安裝了C++開(kāi)發(fā)環(huán)境就可以正常使用
寬轉(zhuǎn)窄:
#include<iostream> #include<atlconv.h> //頭文件 using namespace std; int main() { USES_CONVERSION; //必須添加 wchar_t buf[] = L"哈哈哈哈哈哈"; char *nbuf=W2A(buf); //使用??臻g進(jìn)行轉(zhuǎn)換,不需要delete cout << nbuf << endl; }
窄轉(zhuǎn)寬:
#include<iostream> #include<locale> #include<atlconv.h> //頭文件 using namespace std; int main() { setlocale(LC_ALL,""); //本地化,為輸出漢字 USES_CONVERSION; //必須添加 char buf[] = "哈哈哈哈哈哈"; wchar_t *nbuf=A2W(buf); //使用??臻g進(jìn)行轉(zhuǎn)換,不需要delete wcout << nbuf; }
4.COM組件轉(zhuǎn)換
寬轉(zhuǎn)窄:
#include<comutil.h> #pragma comment(lib, "comsuppw.lib") int main() { wchar_t str[] = L"哈哈哈"; char *s=_com_util::ConvertBSTRToString(str); //轉(zhuǎn)換函數(shù) //其它操作 delete[] s; //釋放內(nèi)存 }
窄轉(zhuǎn)寬:
#include<comutil.h> #pragma comment(lib, "comsuppw.lib") int main() { char str[] = "哈哈哈哈"; wchar_t *s=_com_util::ConvertStringToBSTR(str); //轉(zhuǎn)換函數(shù) //其它操作 SysFreeString(s); //釋放內(nèi)存 }
三.解決VS控制臺(tái)無(wú)法輸出寬字符問(wèn)題
方法一:使用setlocal和printf函數(shù):
#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"哈哈哈哈啊"; }
以上兩種方法,如果寬字符串中沒(méi)有中文字符,則可不使用setlocal函數(shù)
方法三:使用WriteConsoleW函數(shù)
#include<Windows.h> int main() { wchar_t buf[]=L"哈哈哈哈哈哈哈哈哈哈"; WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),buf,sizeof(buf)/2, NULL, 0); }
到此這篇關(guān)于C/C++寬窄字符轉(zhuǎn)換與輸出的多種實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)C/C++寬窄字符轉(zhuǎn)換與輸出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++Primer筆記之關(guān)聯(lián)容器的使用詳解
本篇文章對(duì)C++Primer 關(guān)聯(lián)容器的使用進(jìn)行了詳細(xì)的分析介紹。需要的朋友參考下2013-05-05C++實(shí)現(xiàn)LeetCode(158.用Read4來(lái)讀取N個(gè)字符之二 - 多次調(diào)用)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(158.用Read4來(lái)讀取N個(gè)字符之二 - 多次調(diào)用),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C++中實(shí)現(xiàn)子進(jìn)程執(zhí)行和管道通信詳解
在這篇博客中,我們將深入探索如何在 C++ 程序中實(shí)現(xiàn)子進(jìn)程的創(chuàng)建與執(zhí)行,以及父子進(jìn)程間的管道通信,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01關(guān)于C++11中限定作用域的枚舉類型的問(wèn)題
C++中有兩種類型的枚舉:不限定作用域的枚舉類型和限定作用域的枚舉類型。限定作用域的枚舉類型是C++11標(biāo)準(zhǔn)引入的新類型,對(duì)C++11中限定作用域的枚舉類型相關(guān)知識(shí)感興趣的朋友一起看看吧2022-01-01淺談c語(yǔ)言中轉(zhuǎn)義字符的用法及注意事項(xiàng)
下面小編就為大家?guī)?lái)一篇淺談c語(yǔ)言中轉(zhuǎn)義字符的用法及注意事項(xiàng)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08