網站首頁 編程語言 正文
前言
如果是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);
}
原文鏈接:https://juejin.cn/post/7129055675899969567
相關推薦
- 2022-03-09 C++實現模擬shell命令行(代碼解析)_C 語言
- 2022-09-06 C語言常見排序算法歸并排序_C 語言
- 2022-08-04 Python?threading和Thread模塊及線程的實現_python
- 2022-10-24 UI?開源組件Flutter圖表范圍選擇器使用詳解_Android
- 2022-04-23 uniapp用Promise封裝get和post請求
- 2022-05-10 筆記本能連接 WiFi,但在瀏覽器中并不能訪問網頁的問題的四種方案;
- 2022-08-03 C++中TinyXML讀取xml文件用法詳解_C 語言
- 2022-06-13 C#多線程之Parallel類的用法_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支