C/C++寬窄字符轉換與輸出的多種實現方法
前言
如果是C/C++程序員,對於VS應該是不陌生的,可謂是C/C++程序手中的利器
但如果稍微深入學習就會發現,windows API大部分都是分為寬字節與窄字節的,比如常見的MessageboxA與MessageBoxW函數,這時候就會出現很多問題,最常見的便是亂碼
需要註意的是,WIndows底層函數均采用的是寬字節,即使你使用的是char,程序真正執行的時候,還是會在底層將char轉化為wchar_t,這就意味著使用窄字節效率是比不上寬字節的
同時需要知道.wchar_t是支持多個國傢語言的,而char隻支持本國語言.
一、什麼是寬字節?什麼是窄字節?
認識寬窄字節最好的辦法就是動手實驗一下
可以看到,最直接的影響就是大小,char隻占一個字節,而wchar_t要占兩個字節,並且需要在字符串前加 L 才表示是寬字節
其實還有很多細節,比如這裡是使用的字符c,如果是使用的漢字,還能正常使用嗎?很多問題需要自己碰到並解決,最後才能是自己的東西
二、寬窄字節之間的轉化方法
1.Windows API進行轉化
頭文件:
#include<Windows.h>
用到的函數
窄字節轉寬字節:
int MultiByteToWideChar( UINT CodePage, //要轉換的代碼頁,一般直接填CP_ACP,表示當前系統使用的代碼頁 DWORD dwFlags, //轉換標志,直接填0即可 LPCCH lpMultiByteStr, //要轉換的窄字節字符串 int cbMultiByte, //窄字節字符串的長度,以字節計算 LPWSTR lpWideCharStr, //存放轉換完成的寬字符緩沖區 int cchWideChar //存放寬字符緩沖區的大小 );
寬字節轉窄字節:
int WideCharToMultiByte( UINT CodePage,//要轉換的代碼頁,一般直接填CP_ACP,表示當前系統使用的代碼頁 DWORD dwFlags,//轉換標志,直接填0即可 LPCWCH lpWideCharStr,//要轉換的寬字節字符串 int cchWideChar, //寬字節字符串的長度,以字符計算 LPSTR lpMultiByteStr, //存放轉換完成的窄字符緩沖區 int cbMultiByte, //存放寬字符緩沖區的大小 LPCCH lpDefaultChar, //如果字符無法轉換,則使用該字符填充,一般填0,默認即可 LPBOOL lpUsedDefaultChar //如果出現無法轉換的字符,該參數被設為true,默認填NULL即可 );
一般寬字符是窄字符字節長度的兩倍,但也有可能出現意外情況,或者不想自己計算需要多大的緩沖,則可以調用兩次該函數,第一次返回需要的大小,第二次進行轉換
下面是我封裝的兩個函數,可直接使用,但需要自己delete內存,可以自己使用wstring和string進行替換
窄字節轉寬字節:
//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; }
寬字節轉窄字節
//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緩沖區大小,以字符計算 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緩沖區大小,以字符計算 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++開發環境就可以正常使用
寬轉窄:
#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++寬窄字符轉換與輸出內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- C++實現字符格式相互轉換的示例代碼
- C和C++的區別詳解
- C/C++自主分配出現double free or corruption問題解決
- C++中replace() 函數的基本用法
- 深入學習C++智能指針之shared_ptr與右值引用的方法