C語言MultiByteToWideChar和WideCharToMultiByte案例詳解
注意:
這兩個函數(shù)是由Windows提供的轉(zhuǎn)換函數(shù),不具有通用性
C語言提供的轉(zhuǎn)換函數(shù)為mbstowcs()/wcstombs()
一、函數(shù)簡單介紹
涉及到的頭文件:
函數(shù)所在頭文件:windows.h
#include <windows.h>
wchar_t類型所需頭文件:wchar.h
#include <wchar.h>
( 1 ) MultiByteToWideChar()
函數(shù)功能:該函數(shù)映射一個字符串到一個寬字符(unicode)的字符串。由該函數(shù)映射的字符串沒必要是多字節(jié)字符組。
函數(shù)原型:
int MultiByteToWideChar( UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cchMultiByte, LPWSTR lpWideCharStr, int cchWideChar );
參數(shù):
1> CodePage:指定執(zhí)行轉(zhuǎn)換的多字節(jié)字符所使用的字符集
這個參數(shù)可以為系統(tǒng)已安裝或有效的任何字符集所給定的值。你也可以指定其為下面的任意一值:
Value | Description |
---|---|
CP_ACP | ANSI code page |
CP_MACCP | Not supported |
CP_OEMCP | OEM code page |
CP_SYMBOL | Not supported |
CP_THREAD_ACP | Not supported |
CP_UTF7 | UTF-7 code page |
CP_UTF8 | UTF-8 code page |
2> dwFlags:一組位標(biāo)記,用以指出是否未轉(zhuǎn)換成預(yù)作或?qū)捵址ㄈ艚M合形式存在),是否使用象形文字替代控制字符,以及如何處理無效字符。你可以指定下面是標(biāo)記常量的組合,含義如下:
- MB_PRECOMPOSED:通常使用預(yù)作字符——就是說,由一個基本字符和一個非空字符組成的字符只有一個單一的字符值。這是缺省的轉(zhuǎn)換選擇。不能與MB_COMPOSITE值一起使用。
- MB_COMPOSITE:通常使用組合字符——就是說,由一個基本字符和一個非空字符組成的字符分別有不同的字符值。不能與MB_PRECOMPOSED值一起使用。
- MB_ERR_INVALID_CHARS:如果函數(shù)遇到無效的輸入字符,它將運(yùn)行失敗,且GetLastErro返回ERROR_NO_UNICODE_TRANSLATION值。
- MB_USEGLYPHCHARS:使用象形文字替代控制字符。
組合字符由一個基礎(chǔ)字符和一個非空字符構(gòu)成,每一個都有不同的字符值。每個預(yù)作字符都有單一的字符值給基礎(chǔ)/非空字符的組成。在字符è中,e就是基礎(chǔ)字符,而重音符標(biāo)記就是非空字符。
標(biāo)記MB_PRECOMPOSED和MB_COMPOSITE是互斥的,而標(biāo)記MB_USEGLYPHCHARS和MB_ERR_INVALID_CHARS則不管其它標(biāo)記如何都可以設(shè)置。
一般不使用這些標(biāo)志,故取值為0時。
3> lpMultiByteStr:指向待轉(zhuǎn)換的字符串的緩沖區(qū)。
4> cchMultiByte:指定由參數(shù)lpMultiByteStr指向的字符串中字節(jié)的個數(shù)??梢栽O(shè)置為-1,會自動判斷l(xiāng)pMultiByteStr指定的字符串的長度
(如果字符串不是以空字符中止,設(shè)置為-1可能失敗,可能成功),此參數(shù)設(shè)置為0函數(shù)將失敗。
5> lpWideCharStr:指向接收被轉(zhuǎn)換字符串的緩沖區(qū)。
6> cchWideChar:指定由參數(shù)lpWideCharStr指向的緩沖區(qū)的寬字節(jié)數(shù)。若此值為0,函數(shù)不會執(zhí)行轉(zhuǎn)換,而是返回目標(biāo)緩存lpWideChatStr所需的寬字符數(shù)。
返回值:
如果函數(shù)運(yùn)行成功,并且cchWideChar不為0,返回值是由lpWideCharStr指向的緩沖區(qū)中寫入的寬字符數(shù);
如果函數(shù)運(yùn)行成功,并且cchMultiByte為0,返回值是待轉(zhuǎn)換字符串的緩沖區(qū)所需求的寬字符數(shù)大小。(此種情況用來獲取轉(zhuǎn)換所需的wchar_t的個數(shù))
如果函數(shù)運(yùn)行失敗,返回值為零。
若想獲得更多錯誤信息,請調(diào)用GetLastError()函數(shù)。它可以返回下面所列錯誤代碼:
ERROR_INSUFFICIENT_BUFFER; ERROR_INVALID_FLAGS;
ERROR_INVALID_PARAMETER; ERROR_NO_UNICODE_TRANSLATION。
( 2 ) WideCharToMultiByte()
函數(shù)功能:該函數(shù)映射一個unicode字符串到一個多字節(jié)字符串。
函數(shù)原型:
int WideCharToMultiByte( UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cchMultiByte, LPCSTR lpDefaultChar, LPBOOL pfUsedDefaultChar );
參數(shù):
與MultiByteToWideChar()函數(shù)中的參數(shù)類似,但是多了兩個參數(shù):
lpDefaultChar和pfUsedDefaultChar:只有當(dāng)WideCharToMultiByte函數(shù)遇到一個寬字節(jié)字符,而該字符在uCodePage參數(shù)標(biāo)識的代碼頁中并沒有它的表示法時,WideCharToMultiByte函數(shù)才使用這兩個參數(shù)。(通常都取值為NULL)
1> 如果寬字節(jié)字符不能被轉(zhuǎn)換,該函數(shù)便使用lpDefaultChar參數(shù)指向的字符。如果該參數(shù)是NULL(這是大多數(shù)情況下的參數(shù)值),那么該函數(shù)使用系統(tǒng)的默認(rèn)字符。該默認(rèn)字符通常是個問號。這對于文件名來說是危險(xiǎn)的,因?yàn)閱柼柺莻€通配符。
2> pfUsedDefaultChar參數(shù)指向一個布爾變量,如果Unicode字符串中至少有一個字符不能轉(zhuǎn)換成等價(jià)多字節(jié)字符,那么函數(shù)就將該變量置為TRUE。如果所有字符均被成功地轉(zhuǎn)換,那么該函數(shù)就將該變量置為FALSE。當(dāng)函數(shù)返回以便檢查寬字節(jié)字符串是否被成功地轉(zhuǎn)換后,可以測試該變量。
返回值:
如果函數(shù)運(yùn)行成功,并且cchMultiByte不為零,返回值是由 lpMultiByteStr指向的緩沖區(qū)中寫入的字節(jié)數(shù);
如果函數(shù)運(yùn)行成功,并且cchMultiByte為零,返回值是接收到待轉(zhuǎn)換字符串的緩沖區(qū)所必需的字節(jié)數(shù)。(此種情況用來獲取轉(zhuǎn)換所需Char的個數(shù))
如果函數(shù)運(yùn)行失敗,返回值為零。
若想獲得更多錯誤信息,請調(diào)用GetLastError函數(shù)。它可以返回下面所列錯誤代碼:
ERROR_INSUFFICIENT_BJFFER;ERROR_INVALID_FLAGS; ERROR_INVALID_PARAMETER;ERROR_NO_UNICODE_TRANSLATION。
二、使用方法
( 1 ) 將多字節(jié)字符串轉(zhuǎn)為寬字符串:
1) 調(diào)用MultiByteToWideChar()函數(shù),設(shè)置cchWideChar參數(shù)為0(用以獲取轉(zhuǎn)換所需的接收緩沖區(qū)大?。?;
2) 獲取輸入緩存的大小,作為cchMultiByte的值;(這樣做是為了節(jié)省空間,也可以給cchMultiByte取值-1(字符串需要以空字符結(jié)尾,否則會出錯))
3) 分配足夠的內(nèi)存塊,用于存放轉(zhuǎn)換后的Unicode字符串;
該內(nèi)存塊的大小由前面對cchWideChar()函數(shù)的返回值來決定;(也可以用別的方法,但該方法更節(jié)省內(nèi)存)
4) 再次調(diào)用MultiByteToWideChar()函數(shù),這次將緩存的地址作為lpWideCharStr,參數(shù)來傳遞,并傳遞第一次調(diào)用MultiByteToWideChar()函數(shù)時的返回值作為cchWideChar參數(shù)的值;
5) 使用轉(zhuǎn)換后的字符串;
6) 釋放接收緩沖區(qū)占用的內(nèi)存塊;
示例代碼:
void main() { char sBuf[25]={0}; strcpy(sBuf, "我最棒"); //獲取輸入緩存大小 int sBufSize=strlen(sBuf); //獲取輸出緩存大小 //VC++ 默認(rèn)使用ANSI,故取第一個參數(shù)為CP_ACP DWORD dBufSize=MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, NULL, 0); printf("需要wchar_t%u個\n", dBufSize); wchar_t * dBuf=new wchar_t[dBufSize]; wmemset(dBuf, 0, dBufSize); //進(jìn)行轉(zhuǎn)換 int nRet=MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, dBuf, dBufSize); if(nRet<=0) { cout<<"轉(zhuǎn)換失敗"<<endl; DWORD dwErr=GetLastError(); switch(dwErr) { case ERROR_INSUFFICIENT_BUFFER: printf("ERROR_INSUFFICIENT_BUFFER\n"); break; case ERROR_INVALID_FLAGS: printf("ERROR_INVALID_FLAGS\n"); break; case ERROR_INVALID_PARAMETER: printf("ERROR_INVALID_PARAMETER\n"); break; case ERROR_NO_UNICODE_TRANSLATION: printf("ERROR_NO_UNICODE_TRANSLATION\n"); break; } } else { cout<<"轉(zhuǎn)換成功"<<endl; cout<<dBuf; } delete(dBuf); }
注意:兩次調(diào)用MultiCharToWideChar()時,形參cchMultiByte的取值需要相同,否則可能會出現(xiàn)接收緩存不足之類的錯誤,從而導(dǎo)致轉(zhuǎn)換失?。?/p>
( 2 ) 從寬字節(jié)轉(zhuǎn)為窄字節(jié)字符串
步驟與(1)類似,故不贅述
代碼示例如下:
//從寬字符串轉(zhuǎn)換窄字符串 wchar_t sBuf[25]={0}; wcscpy(sBuf, L"我最棒"); //獲取轉(zhuǎn)換所需的目標(biāo)緩存大小 DWORD dBufSize=WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, NULL,0,NULL, FALSE); //分配目標(biāo)緩存 char *dBuf = new char[dBufSize]; memset(dBuf, 0, dBufSize); //轉(zhuǎn)換 int nRet=WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, dBuf, dBufSize, NULL, FALSE); if(nRet<=0) { printf("轉(zhuǎn)換失敗\n"); } else { printf("轉(zhuǎn)換成功\nAfter Convert: %s\n", dBuf); } delete []dBuf;
三、MultiByteToWideChar()函數(shù)亂碼的問題
有的朋友可能已經(jīng)發(fā)現(xiàn),在標(biāo)準(zhǔn)的WinCE4.2或WinCE5.0 SDK模擬器下,這個函數(shù)都無法正常工作,其轉(zhuǎn)換之后的字符全是亂碼!
及時更改MultiByteToWideChar()參數(shù)也依然如此。不過這個不是代碼問題,其結(jié)癥在于所定制的操作系統(tǒng).如果我們定制的操作系統(tǒng)默認(rèn)語言不是中文,也會出現(xiàn)這種情況。
由于標(biāo)準(zhǔn)的SDK默認(rèn)語言為英文,所以肯定會出現(xiàn)這個問題。而這個問題的解決,不能在簡單地更改控制面板的”區(qū)域選項(xiàng)”的”默認(rèn)語言”,而是要在系統(tǒng)定制的時候,選擇默認(rèn)語言為”中文”。系統(tǒng)定制時選擇默認(rèn)語言的位置于: Platform -> Setting… -> locale -> default language ,選擇”中文”,然后編譯即可。
Unicode :寬字節(jié)字符集
1.如何取得一個既包含單字節(jié)字符又包含雙字節(jié)字符的字符串的字符個數(shù)?
可以調(diào)用Microsoft Visual C++的運(yùn)行期庫包含函數(shù)_mbslen來操作多字節(jié)(既包括單字節(jié)也包括雙字節(jié))字符串。
調(diào)用strlen函數(shù),無法真正了解字符串中究竟有多少字符,它只能告訴你到達(dá)結(jié)尾的0之前有多少個字節(jié)。
2.如何對DBCS(雙字節(jié)字符集)字符串進(jìn)行操作?
函數(shù) 描述
PTSTR CharNext ( LPCTSTR ); 返回字符串中下一個字符的地址
PTSTR CharPrev ( LPCTSTR, LPCTSTR ); 返回字符串中上一個字符的地址BOOL IsDBCSLeadByte( BYTE ); 如果該字節(jié)是DBCS字符的第一個字節(jié),則返回非0值
3.為什么要使用Unicode?
可以很容易地在不同語言之間進(jìn)行數(shù)據(jù)交換。
使你能夠分配支持所有語言的單個二進(jìn)制.exe文件或DLL文件。
提高應(yīng)用程序的運(yùn)行效率。
Windows 2000是使用Unicode從頭進(jìn)行開發(fā)的,如果調(diào)用任何一個Windows函數(shù)并給它傳遞一個ANSI字符串,那么系統(tǒng)首先要將字符串轉(zhuǎn)換成Unicode,然后將Unicode字符串傳遞給操作系統(tǒng)。如果希望函數(shù)返回ANSI字符串,系統(tǒng)就會首先將Unicode字符串轉(zhuǎn)換成ANSI字符串,然后將結(jié)果返回給你的應(yīng)用程序。進(jìn)行這些字符串的轉(zhuǎn)換需要占用系統(tǒng)的時間和內(nèi)存。通過從頭開始用Unicode來開發(fā)應(yīng)用程序,就能夠使你的應(yīng)用程序更加有效地運(yùn)行。
Windows CE 本身就是使用Unicode的一種操作系統(tǒng),完全不支持ANSI Windows函數(shù)
Windows 98 只支持ANSI,只能為ANSI開發(fā)應(yīng)用程序。
Microsoft公司將COM從16位Windows轉(zhuǎn)換成Win32時,公司決定需要字符串的所有COM接口方法都只能接受Unicode字符串。
4.如何編寫Unicode源代碼?
Microsoft公司為Unicode設(shè)計(jì)了WindowsAPI,這樣,可以盡量減少代碼的影響。實(shí)際上,可以編寫單個源代碼文件,以便使用或者不使用Unicode來對它進(jìn)行編譯。只需要定義兩個宏(UNICODE和_UNICODE),就可以修改然后重新編譯該源文件。
_UNICODE宏用于C運(yùn)行期頭文件,而UNICODE宏則用于Windows頭文件。當(dāng)編譯源代碼模塊時,通常必須同時定義這兩個宏。
5.Windows定義的Unicode數(shù)據(jù)類型有哪些?
數(shù)據(jù)類型 說明
WCHAR Unicode字符
PWSTR 指向Unicode字符串的指針
PCWSTR 指向一個恒定的Unicode字符串的指針
對應(yīng)的ANSI數(shù)據(jù)類型為CHAR,LPSTR和LPCSTR。
ANSI/Unicode通用數(shù)據(jù)類型為TCHAR,PTSTR,LPCTSTR。
6.如何對Unicode進(jìn)行操作?
字符集 特性 實(shí)例
ANSI 操作函數(shù)以str開頭 strcpy
Unicode 操作函數(shù)以wcs開頭 wcscpy
MBCS 操作函數(shù)以_mbs開頭 _mbscpy
ANSI/Unicode 操作函數(shù)以_tcs開頭 _tcscpy(C運(yùn)行期庫)
ANSI/Unicode 操作函數(shù)以lstr開頭 lstrcpy(Windows函數(shù))
所有新的和未過時的函數(shù)在Windows2000中都同時擁有ANSI和Unicode兩個版本。ANSI版本函數(shù)結(jié)尾以A表示;Unicode版本函數(shù)結(jié)尾以W表示。Windows會如下定義:
#ifdef UNICODE #define CreateWindowEx CreateWindowExW #else #define CreateWindowEx CreateWindowExA #endif // !UNICODE
7.列表內(nèi)容
如何表示Unicode字符串常量?
字符集 實(shí)例
ANSI “string”
Unicode L“string”
ANSI/Unicode T(“string”)或_TEXT(“string”)if( szError[0] == _TEXT(‘J') ){ }
7. 為什么應(yīng)當(dāng)盡量使用操作系統(tǒng)函數(shù)?
這將有助于稍稍提高應(yīng)用程序的運(yùn)行性能,因?yàn)椴僮飨到y(tǒng)字符串函數(shù)常常被大型應(yīng)用程序比如操作系統(tǒng)的外殼進(jìn)程Explorer.exe所使用。由于這些函數(shù)使用得很多,因此,在應(yīng)用程序運(yùn)行時,它們可能已經(jīng)被裝入RAM。
如:StrCat,StrChr,StrCmp和StrCpy等。
8. 如何編寫符合ANSI和Unicode的應(yīng)用程序?
(1) 將文本串視為字符數(shù)組,而不是chars數(shù)組或字節(jié)數(shù)組。
(2) 將通用數(shù)據(jù)類型(如TCHAR和PTSTR)用于文本字符和字符串。
(3) 將顯式數(shù)據(jù)類型(如BYTE和PBYTE)用于字節(jié)、字節(jié)指針和數(shù)據(jù)緩存。
(4) 將TEXT宏用于原義字符和字符串。
(5) 執(zhí)行全局性替換(例如用PTSTR替換PSTR)。
(6) 修改字符串運(yùn)算問題。例如函數(shù)通常希望在字符中傳遞一個緩存的大小,而不是字節(jié)。這意味著不應(yīng)該傳遞sizeof(szBuffer),而應(yīng)該傳遞(sizeof(szBuffer)/sizeof(TCHAR)。另外,如果需要為字符串分配一個內(nèi)存塊,并且擁有該字符串中的字符數(shù)目,那么請記住要按字節(jié)來分配內(nèi)存。這就是說,應(yīng)該調(diào)用malloc(nCharacters *sizeof(TCHAR)),而不是調(diào)用malloc(nCharacters)。
9. 列表內(nèi)容
如何對字符串進(jìn)行有選擇的比較?
通過調(diào)用CompareString來實(shí)現(xiàn)。
標(biāo)志 含義
NORM_IGNORECASE 忽略字母的大小寫
NORM_IGNOREKANATYPE 不區(qū)分平假名與片假名字符
NORM_IGNORENONSPACE 忽略無間隔字符
NORM_IGNORESYMBOLS 忽略符號
NORM_IGNOREWIDTH 不區(qū)分單字節(jié)字符與作為雙字節(jié)字符的同一個字符
SORT_STRINGSORT 將標(biāo)點(diǎn)符號作為普通符號來處理
10. . 如何判斷一個文本文件是ANSI還是Unicode?
判斷如果文本文件的開頭兩個字節(jié)是0xFF和0xFE,那么就是Unicode,否則是ANSI。
11. 如何判斷一段字符串是ANSI還是Unicode?
用IsTextUnicode進(jìn)行判斷。IsTextUnicode使用一系列統(tǒng)計(jì)方法和定性方法,以便猜測緩存的內(nèi)容。由于這不是一種確切的科學(xué)方法,因此 IsTextUnicode有可能返回不正確的結(jié)果。
12. 如何在Unicode與ANSI之間轉(zhuǎn)換字符串?
Windows函數(shù)MultiByteToWideChar用于將多字節(jié)字符串轉(zhuǎn)換成寬字符串;函數(shù)WideCharToMultiByte將寬字符串轉(zhuǎn)換成等價(jià)的多字節(jié)字符串。
到此這篇關(guān)于C語言MultiByteToWideChar和WideCharToMultiByte案例詳解的文章就介紹到這了,更多相關(guān)C語言MultiByteToWideChar和WideCharToMultiByte內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android選擇與上傳圖片之PictureSelector教程
- C++使用WideCharToMultiByte函數(shù)生成UTF-8編碼文件的方法
- SpringCloud2020.0.x版UnderTow AccessLog相關(guān)配置簡介
- 解決SpringBoot加載application.properties配置文件的坑
- C語言container of()函數(shù)案例詳解
- gaussdb 200安裝 data studio jdbc idea鏈接保姆級安裝步驟
- OpenCV實(shí)現(xiàn)特征檢測和特征匹配方法匯總
- easycom模式開發(fā)UNI-APP組件調(diào)用必須掌握的實(shí)用技巧
- Android選擇與上傳圖片之ImagePicker教程
- Android選擇與上傳圖片之Matisse教程
相關(guān)文章
C++類與對象及構(gòu)造函數(shù)析構(gòu)函數(shù)基礎(chǔ)詳解
這篇文章主要為大家介紹了C++類與對象及構(gòu)造函數(shù)析構(gòu)函數(shù)基礎(chǔ)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04OpenCV實(shí)現(xiàn)特征檢測和特征匹配方法匯總
一幅圖像中總存在著其獨(dú)特的像素點(diǎn),這些點(diǎn)我們可以認(rèn)為就是這幅圖像的特征,成為特征點(diǎn),本文主要介紹了OpenCV實(shí)現(xiàn)特征檢測和特征匹配方法,感興趣的可以了解一下2021-08-08C語言中static的作用及C語言中使用靜態(tài)函數(shù)有何好處
在C語言中,static的作用有三條:一是隱藏功能,二是保持持久性功能,三是默認(rèn)初始化為0。本文重點(diǎn)給大家介紹C語言中static的作用及c語言中使用靜態(tài)函數(shù)有何好處,對本文感興趣的朋友一起看看吧2015-11-11C語言每日練習(xí)之動態(tài)顯示系統(tǒng)時間
這篇文章主要介紹了C語言動態(tài)顯示系統(tǒng)時,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11C++實(shí)現(xiàn)教職工信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)教職工信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C語言三個數(shù)排列大小的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄狢語言三個數(shù)排列大小的實(shí)現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06