UINCODE字符串和安全字符串函数(好)
[原]UINCODE字符串和安全字符串函數(shù)
字符集基礎(chǔ)知識(shí)
在計(jì)算機(jī)中,字符都是以二進(jìn)制編碼方式存在于存儲(chǔ)中
編碼與解碼
將字符輸入計(jì)算機(jī)存儲(chǔ)的過程類似于一個(gè)”編碼”的過程
而將對(duì)應(yīng)的”編碼”顯示出來的過程類似于一個(gè)解碼的過程
?
二進(jìn)制值本身代表什么含義是可以隨意定義的,在內(nèi)存中用某個(gè)2進(jìn)制的值代表某一個(gè)值,
比如說用8位2進(jìn)制的代表單字節(jié)這些,16位,32位等等
用某個(gè)二進(jìn)制值表示某個(gè)字符完全是人為設(shè)定的,最終字符集就是字符到其二進(jìn)制數(shù)字值得映射
?
單字節(jié)字符集(SBCS) ?Single Byte Character Set
單字節(jié)字符集使用一個(gè)字節(jié)(8Bits)編碼字符
最大可編碼256個(gè)字符
有名的單字節(jié)字符集就是ASCII碼
字符集的變體稱為代碼頁,主要包括不同的特殊字符,一般為一種語言或語言組定制
用在美國的OEM代碼頁標(biāo)識(shí)符是437
調(diào)用GetACP函數(shù)可以檢索系統(tǒng)中ANSI代碼頁標(biāo)識(shí)符
使用GetOEMCP可以得到OEM代碼頁標(biāo)識(shí)符
OemToChar和OemToCharBuff函數(shù)可以把字符或串從OEM頁轉(zhuǎn)到ANSI代碼頁
反之用CharToOem或CharToOemBuff
GetCpInfo函數(shù)可以得到代碼頁中的詳細(xì)信息:最大字符大小、缺省字符、前置符(詳見CPINFO結(jié)構(gòu)體)
使用MultiByteToWideChar可以把單字節(jié)字符或串轉(zhuǎn)換到UNICODE反之用WideCharToMultiByte
雙字節(jié)字符集(DBCS)?Double Byte Character Set
雙字節(jié)字符集被稱作擴(kuò)展的8Bits字符集,最小單位仍是一個(gè)字節(jié)
Windows亞洲語言版中一般都支持ANSI字符集和DBCS
在這些平臺(tái)的程序中需要特別的算法處理DBCS
使用IsDBCSLeadByte可以判定所給字符是否是雙字節(jié)字符的第一個(gè)字節(jié)
使用MultiByteToWideChar可以將雙字節(jié)字符或串轉(zhuǎn)換為UNICODE
反之使用WideCharToMultiByte
有些字符集編碼甚至使用4Bytes表示一個(gè)字符,此時(shí)統(tǒng)稱為多字節(jié)字符集MBCS(MultiBytes Char Set)
常用字符集和字符編碼
ASCII字符集
GB2312字符集(國標(biāo)碼)
GB18030字符集
Unicode字符集
?
ASCII字符集
ASCII(AmericanStandard Code for Information Interchange,美國信息交換標(biāo)準(zhǔn)代碼)
是基于拉丁字母的一套字符編碼
主要用于顯示現(xiàn)代英語,而其擴(kuò)展版本EASCII則可以勉強(qiáng)顯示其他西歐語言。它是現(xiàn)今最通用的單字節(jié)編碼系統(tǒng)
等同于國際標(biāo)準(zhǔn)ISO/IEC 646
將ASCII字符集轉(zhuǎn)換為計(jì)算機(jī)可以接受的數(shù)字系統(tǒng)的數(shù)的規(guī)則。使用7位(bits)表示一個(gè)字符,共128字符;
為了表示更多的歐洲常用字符對(duì)ASCII進(jìn)行了擴(kuò)展,ASCII擴(kuò)展字符集使用8位(bits)表示一個(gè)字符,共256字符。
ASCII的最大缺點(diǎn)是只能顯示26個(gè)基本拉丁字母、阿拉伯?dāng)?shù)目字和英式標(biāo)點(diǎn)符號(hào),因此只能用于顯示現(xiàn)代美國英語(而且在處理英語當(dāng)中的外來詞如na?ve、café、élite等等時(shí),所有重音符號(hào)都不得不去掉,即使這樣做會(huì)違反拼寫規(guī)則)。
而EASCII雖然解決了部份西歐語言的顯示問題,但對(duì)更多其他語言依然無能為力。
GBXXXX字符集 (國標(biāo)字符集)
因ASCII碼的限制,為了顯示中文,必須設(shè)計(jì)一套編碼規(guī)則用于將漢字轉(zhuǎn)換為計(jì)算機(jī)可以接受的數(shù)字系統(tǒng)的數(shù)。
為此規(guī)定那些127號(hào)之后的奇異符號(hào)(即EASCII)取消掉,同時(shí)規(guī)定:一個(gè)小于127的字符的意義與原來相同,但兩個(gè)大于127的字符連在一起時(shí),就表示一個(gè)漢字,前面的一個(gè)字節(jié)(他稱之為高字節(jié))從0xA1用到 0xF7,后面一個(gè)字節(jié)(低字節(jié))從0xA1到0xFE,這樣可以組合出大約7000多個(gè)簡體漢字
上述規(guī)則即為GB2312中國國家標(biāo)準(zhǔn)簡體中文字符集GBO
對(duì)于人名、古漢語等方面出現(xiàn)的罕用字,GB2312不能處理,這導(dǎo)致了后來GBK及GB 18030漢字字符集的出現(xiàn)
GB18030字符集
國家標(biāo)準(zhǔn)GB 18030-2005《信息技術(shù) 中文編碼字符集》
與GB 2312-1980完全兼容,與GBK基本兼容,支持GB 13000及Unicode的全部統(tǒng)一漢字,共收錄漢字70244個(gè)
特點(diǎn):
n? 與UTF-8相同,采用多字節(jié)編碼,每個(gè)字可以由1個(gè)、2個(gè)或4個(gè)字節(jié)組成。
n? 編碼空間龐大,最多可定義161萬個(gè)字符。
n? 支持中國國內(nèi)少數(shù)民族的文字,不需要?jiǎng)佑迷熳謪^(qū)。
n? 漢字收錄范圍包含繁體漢字以及日韓漢字
Unicode字符集
當(dāng)計(jì)算機(jī)傳到世界各個(gè)國家時(shí),為了適合當(dāng)?shù)卣Z言設(shè)計(jì)和實(shí)現(xiàn)很多不同的編碼方案。
在本地使用沒有問題,一旦出現(xiàn)在網(wǎng)絡(luò)中,由于不兼容,互相訪問就出現(xiàn)了亂碼現(xiàn)象。
為了解決這個(gè)問題,一個(gè)偉大的創(chuàng)想產(chǎn)生了——Unicode
UNICODE標(biāo)準(zhǔn)前身是通用字符集(Universal Character Set)UCS
現(xiàn)在標(biāo)準(zhǔn)由UNICODE聯(lián)盟維護(hù),官方網(wǎng)址:www.unicode.org 目前最新的標(biāo)準(zhǔn)版本是7.0 ?(2015.01.16)
最初的UNICODE使用兩個(gè)字節(jié)編碼字符集, 現(xiàn)在已被新的編碼方式取代
Windows支持UNICODE字符集及全部編碼方式
UNICODE詳解
Unicode是國際組織制定的可以容納世界上所有文字和符號(hào)的字符編碼方案。
Unicode用數(shù)字0-0x10FFFF來映射這些字符,最多可以容納1114112個(gè)字符,或者說有1114112個(gè)碼位。
碼位就是可以分配給字符的數(shù)字。UTF-8、UTF-16、UTF-32都是將數(shù)字轉(zhuǎn)換到程序數(shù)據(jù)的編碼方案。
通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或稱ISO/IEC 10646)標(biāo)準(zhǔn)所定義的標(biāo)準(zhǔn)字符集。UCS-2用兩個(gè)字節(jié)編碼,UCS-4用4個(gè)字節(jié)編碼。
現(xiàn)在UCS和UNICODE基本合二為一?
與其它的直接指定式編碼字符集不同,UNICODE是字符集,UTF-x是編碼方式
一般情況下:一個(gè)字符對(duì)應(yīng)到一些位(bits). 如: A -> 0100 0001
而在 Unicode 中, 一個(gè)字符實(shí)際上對(duì)應(yīng)一種叫做 code point 的東西。
每一個(gè)字母表中的抽象的字母,都被賦予了一個(gè)數(shù)字,比如 U+0645. 這個(gè)叫做 code point.
U+ 表示: Unicode, 數(shù)字是 16 進(jìn)制的。
Unicode 中 code point 的數(shù)字的大小是沒有限制的,而且也早就超過了 65535. 所以不是每個(gè)字符都能存儲(chǔ)在兩個(gè)字節(jié)中。
運(yùn)行CharMap程序可以查看U+形式的字符詳細(xì)信息?CMD
使用UNICODE的好處
Windows從NT內(nèi)核版本開始所有平臺(tái)均完全基于UNICODE打造
使用UNICODE版API節(jié)約了字符轉(zhuǎn)換的額外開銷,從根本上保證了程序能夠最高效的利用API的性能
UNICODE函數(shù)不再考慮因字符不同而帶來的字符串長不確定的問題(這曾是程序員的噩夢(mèng))
UNICODE編碼的標(biāo)準(zhǔn)唯一性使得UNICODE具有非常好的可移植性
允許同時(shí)顯示不同國家的不同語言的字符在一個(gè)程序中
Windows API 與 UNICODE
Windows平臺(tái)提供3種關(guān)于字符操作相關(guān)API的封裝形式
n? 一般宏定義形式API(兼容UNICODE和非UNICODE)
n? 以A結(jié)尾的非UNICODE版API
n? 以W結(jié)尾的UNICODE版API
Windows內(nèi)部其實(shí)僅提供了UNICODE版的API,非UNICODE版的API在內(nèi)部先將參數(shù)轉(zhuǎn)換成UNICODE串,然后再調(diào)用UNICODE版的API,如果返回結(jié)果仍然是UNICODE,那么就再進(jìn)行反向轉(zhuǎn)換
兼容版的API在編譯時(shí),如果指定了UNICODE宏,那么就替換成UNICODE版的API否則就替換成非UNICODE版的API
由此可見調(diào)用非UNICODE版的API會(huì)付出額外的代價(jià),當(dāng)字符串較長,或者調(diào)用較多時(shí),性能損失還是比較明顯的
綜上本課程提倡使用兼容版API宏定義,并且使用UNICODE宏和_UNICODE宏編譯VC代碼
VC中默認(rèn)采用的是UTF-16編碼方式,因此一個(gè)UNICODE字符占用2字節(jié)
VC中非UNICODE的串統(tǒng)稱為MBCS(多字節(jié)字符集)
?
Windows平臺(tái)的UNICODE串函數(shù)(API)
strlen函數(shù)返回字符串中的字節(jié)數(shù),而lstrlen返回字符數(shù),不管字符是1字節(jié)還是2字節(jié)
與標(biāo)準(zhǔn)C庫函數(shù)tolower或toupper不同,CharLower或CharUpper可以作用于字符集中的任何字符(包括非英文字符等,比如?和?)
wsprintf和wvsprintf是標(biāo)準(zhǔn)C函數(shù)sprintf和vsprintf的擴(kuò)展(API)
也是僅有的兩個(gè)支持格式說明的UNICODE版函數(shù)
?
系統(tǒng)本地語言支持(National Language Support)
系統(tǒng)本地標(biāo)示符,是一個(gè)語言/子語言標(biāo)示符和結(jié)合到一個(gè)雙字值中的保留字
通過該標(biāo)示符,應(yīng)用程序可以進(jìn)一步得到系統(tǒng)安裝的語言版本,系統(tǒng)區(qū)域設(shè)置等信息(比如中文版Windows,時(shí)區(qū)是東8區(qū))
通過調(diào)用GetSystemDefaultLCID和GetUserDefaultLCID函數(shù)可以獲得區(qū)域信息標(biāo)識(shí)符
要獲得本地語言標(biāo)識(shí)符可以調(diào)用GetSystemDefaultLangID和GetUserDefaultLangID
得到區(qū)域信息有助于調(diào)用一些與區(qū)域信息相關(guān)的API:比如獲取日期時(shí)間格式、貨幣格式等
這些是一些高級(jí)國際化軟件必需要使用的信息
關(guān)于這組函數(shù)的調(diào)用,將在需要調(diào)用時(shí)進(jìn)行介紹
如何正確使用兼容版字符集編程
???????? TCHAR -> char or wchar_t
???????? LPTSTR-> char* or wchar_t*
???????? LPTCH->char* or wchar_t*
???????? LPCTSTR->const char* or constwchar_t* or LPCSTR等
???????? 使用_T()宏包裹字符或串常量
使用C標(biāo)準(zhǔn)庫字符串函數(shù)時(shí)的幾個(gè)問題
如果不調(diào)用setlocale方法,標(biāo)準(zhǔn)庫函數(shù)對(duì)串的字符集解釋可能不正確而輸出亂碼(TCHAR版:_tsetlocale)
對(duì)于含有非ASCII碼的串,調(diào)用strlen時(shí)返回的是字符串的字節(jié)長度,而不是字符數(shù)(因?yàn)橛行┳址嵌鄠€(gè)字節(jié),因此字節(jié)數(shù)不等于字符數(shù))
使用MBCS版的庫函數(shù)就可以正確偵測(cè)到含有多字節(jié)字符的串中的字符數(shù)
即使使用UNICODE和_UNICODE宏(或MBCS和_MBCS)編譯的項(xiàng)目代碼,仍然可以使用非UNICODE版或純UNICODE版的函數(shù),這個(gè)宏其實(shí)僅對(duì)TCHAR.h中和Windows.h中的宏定義起作用,對(duì)原函數(shù)無任何影響(對(duì)Windows API也成立)
字符集的轉(zhuǎn)換
有些情況下,需要在各種不同的字符集之間轉(zhuǎn)換字符串,甚至需要在不同的編碼方式間進(jìn)行轉(zhuǎn)換
此時(shí)可以調(diào)用C庫函數(shù)mbstowcs或wcstombs等進(jìn)行轉(zhuǎn)換
或者可以用Windows API:MultiByteToWideChar或WideCharToMultiByte進(jìn)行相互轉(zhuǎn)換
利用OemToChar可以將一個(gè)OEM版字符串轉(zhuǎn)換成ANSI串或?qū)捵止?jié)字符串,反之用CharToOem
傳統(tǒng)C庫函數(shù)的一些安全問題
在微軟產(chǎn)品的安全漏洞中,有很大一部分是由于使用C標(biāo)準(zhǔn)庫(C Runtime Library)的函數(shù),特別是有關(guān)字符串處理的函數(shù)導(dǎo)致的;(數(shù)組下標(biāo)越界)
多數(shù)是因?yàn)榫彌_區(qū)溢出導(dǎo)致執(zhí)行惡意代碼,從而提升了權(quán)限,進(jìn)而進(jìn)行惡意攻擊;
這一點(diǎn)并不奇怪,因?yàn)镃標(biāo)準(zhǔn)庫函數(shù)的設(shè)計(jì)大約是30年前的事情了;當(dāng)時(shí)并沒有太多安全方面的考慮;
在http://msdn.microsoft.com/en-us/library/bb288454.aspx有一個(gè)完整的不安全C庫函數(shù)的列表
從VS2005起,如果C/C++代碼中使用了這些函數(shù),編譯器都會(huì)提示一個(gè)C4996的不安全函數(shù)引用警告
非服務(wù)端軟件可以關(guān)閉或直接忽略這個(gè)警告
安全字符串函數(shù)
作為非安全字符串的替代,可以在VS2005(及以上版本中)調(diào)用兩組安全的字符串操作函數(shù):
StringSafe Functions(微軟提供的內(nèi)聯(lián)形式函數(shù),可以當(dāng)做API)
SafeCRT(C庫函數(shù))
其它的一些安全函數(shù)替代品
一般使用帶有_s結(jié)尾的新版C庫函數(shù),替代原有的C庫函數(shù),如:用fopen_s替代fopen或wfopen_s替代wfopen等
如果是Windows平臺(tái)的程序,可用類似功能的API替代C庫函數(shù),如:用CreateFile代替fopen,wfopen等;
要使用String Safe函數(shù),只需包含strsafe.h即可
使用Safe CRT函數(shù),需查看MSDN以確定需要包含的頭文件
使用安全字符串函數(shù)的一些需考慮問題
StringSafe 函數(shù)因?yàn)槭褂玫氖莾?nèi)聯(lián)方式,因此可以直接使用,并具備一定的平臺(tái)無關(guān)性(推薦使用)
Safe CRT是正在考察的標(biāo)準(zhǔn)庫函數(shù),因此不同編譯環(huán)境中細(xì)節(jié)上可能還有差異(詳情見相應(yīng)環(huán)境的幫助文檔)
對(duì)于客戶端軟件或單機(jī)軟件可以不考慮使用安全字符串函數(shù),仍可使用傳統(tǒng)的C庫函數(shù)或C++字符串類
在安全性要求較高的環(huán)境中,比如服務(wù)端軟件中,盡力避免使用stl中的string類或MFC/ATL中的CString類,需要使用時(shí)考慮使用安全字符串操作函數(shù)自行封裝,同時(shí)避免使用非安全的庫函數(shù)(Windows平臺(tái)上的網(wǎng)絡(luò)服務(wù)應(yīng)用尤其要避免使用非安全的字符串函數(shù)或字符串類)
安全字符串函數(shù)因具備緩沖區(qū)安全檢測(cè)機(jī)制,所以有一定性能損失,但損失不大可以忽略(詳細(xì)情況可以使用VS2008自帶性能分析工具進(jìn)行分析比較)
ATL庫中字符串轉(zhuǎn)換的支持
ATL庫中的字符串轉(zhuǎn)換通過宏定義在頭文件atlconv.h中
此頭文件可以單獨(dú)使用,不需要其它的ATL組件或頭文件支持
使用時(shí)需要先調(diào)用一個(gè)宏USES_CONVERSION;然后就可以調(diào)用A2T,A2W,W2T,W2A等宏進(jìn)行字符串轉(zhuǎn)換
?
?
?
示例
UNICODE版API調(diào)用示例
#include <tchar.h> #include <windows.h> #include <locale.h> #include <malloc.h>int _tmain() {_tsetlocale(LC_ALL,_T("chs"));//大小寫轉(zhuǎn)換 針對(duì)多字節(jié)字符TCHAR chLower[] = _T("abc αβγδεζνξοπρσηθικλμτυφχψω");TCHAR *chUpper = NULL;_tprintf(_T("Lower Char = %s\n"),chLower);//裝換為大寫的chUpper = CharUpper(chLower);_tprintf(_T("Upper Char = %s\n"),chUpper);_tprintf(_T("Upper Char Point = 0x%08X,Lower Char Point = 0x%08X\n"),chUpper,chLower);//裝換為小寫的CharLower(chUpper);_tprintf(_T("Convert Lower Char = %s\n"),chLower);TCHAR pString[] = _T("一二三趙錢孫李A(yù)BCabc1231234");//字符長度int iLen = lstrlen(pString);TCHAR* pNext = pString;TCHAR* pPrev = pString + sizeof(pString)/sizeof(pString[0]) - 1; for(int i = 0;i < iLen; i ++){pPrev = CharPrev(pString,pPrev);_tprintf(_T("Next Char='%c'\tPrev Char='%c'"),*pNext,*pPrev);if(IsCharAlpha(*pNext)){_tprintf(_T("\tNext Char is Alpha"));}else if(IsCharAlphaNumeric(*pNext)){_tprintf(_T("\tNext Char is Alpha Numeric"));}else{_tprintf(_T("\tNext Char is Unknown Type"),*pNext);}if(IsCharLower(*pNext)){_tprintf(_T("\tNext Char is Lower\n"));}else if(IsCharUpper(*pNext)){_tprintf(_T("\tNext Char is Upper\n"));}else{_tprintf(_T("\tNext Char is no Lower or Upper\n"),*pNext);}pNext = CharNext(pNext);}_tsystem(_T("PAUSE"));return 0; }系統(tǒng)本地語言支持(查看本地的語言的示例)
#include <tchar.h> #include <windows.h> #include <strsafe.h>BOOL CALLBACK EnumCodePagesProc(LPTSTR lpCodePageString) {const int iBufLen = 1024;TCHAR pBuff[iBufLen];size_t szLen = 0;CPINFOEX ci = {};GetCPInfoEx((UINT)_ttoi(lpCodePageString),0,&ci);StringCchPrintf(pBuff,iBufLen,_T("CP:%5s\tCP Name:%s\n\ Max Char Size:%uBytes Default Char:0x%02X%02X Lead Byte:0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X Unicode Default Char:%c CP:%u\n\ -------------------------------------------------------------------------------------------------------------------------------------------\n"),lpCodePageString,ci.CodePageName,ci.MaxCharSize,ci.DefaultChar[0],ci.DefaultChar[1],ci.LeadByte[0],ci.LeadByte[1],ci.LeadByte[2],ci.LeadByte[3],ci.LeadByte[4],ci.LeadByte[5],ci.LeadByte[6],ci.LeadByte[7],ci.LeadByte[8],ci.LeadByte[9],ci.LeadByte[10],ci.LeadByte[11],ci.UnicodeDefaultChar,ci.CodePage);StringCchLength(pBuff,iBufLen,&szLen);WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),pBuff,szLen,NULL,NULL);return TRUE; }int _tmain() {COORD cd = {156,1024};SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),cd);TCHAR psInstalled[] = _T("Installed Code Pages:\n\ -------------------------------------------------------------------------------------------------------------------------------------------\n"); WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),psInstalled,sizeof(psInstalled)/sizeof(psInstalled[0]) - 1,NULL,NULL);EnumSystemCodePages(EnumCodePagesProc,CP_INSTALLED);_tsystem(_T("PAUSE"));TCHAR psAll[] = _T("All Supported Code Pages:\n\ -------------------------------------------------------------------------------------------------------------------------------------------\n"); WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),psAll,sizeof(psAll)/sizeof(psAll[0]) - 1,NULL,NULL);EnumSystemCodePages(EnumCodePagesProc,CP_SUPPORTED);_tsystem(_T("PAUSE"));return 0; }調(diào)用C庫函數(shù)的例子
#include <tchar.h> #include <windows.h> #include <stdio.h> #include <locale.h> #include <mbstring.h>int _tmain() {_tsetlocale(LC_ALL,_T("chs"));TCHAR pszTest[] = _T("123Abc漢字€鴕㎜㎎㊣㎞㏄㏑㏕㏒");_tprintf(_T("Len=%d; %s\n"),_tcslen(pszTest),pszTest); #ifdef _UNICODEwprintf(L"Len=%d; wprintf->:%s\n",wcslen(pszTest),pszTest); #elseprintf("Len=%d; printf->:%s\n",strlen(pszTest),pszTest); #endifchar pszAString[] = "123Abc漢字€鴕㎜㎎㊣㎞㏄㏑㏕㏒";printf("MBCS(ANSI)->:Len=%d; %s\n",strlen(pszAString),pszAString);wchar_t pszWString[] = L"123Abc漢字€鴕㎜㎎㊣㎞㏄㏑㏕㏒";wprintf(L"UNICODE->:Len=%d; %s\n",wcslen(pszWString),pszWString);printf("MBCS Len = %d And Unicode Len = %d : %s\n",_mbslen((const unsigned char*)pszAString),wcslen(pszWString),pszAString);_tsystem(_T("PAUSE"));return 0; }字符集轉(zhuǎn)換示例
?
#include <tchar.h> #include <windows.h> #include <stdio.h> #include <locale.h> #include <mbstring.h>int _tmain() {_tsetlocale(LC_ALL,_T("chs"));char pStringA[] = "123ABC漢字абвгде╔╗╚╝╠╣╦";printf("轉(zhuǎn)換前:%s\n",pStringA);wchar_t pStringW[256] = {};MultiByteToWideChar( CP_ACP, 0, pStringA,strlen(pStringA)+1, pStringW, sizeof(pStringW)/sizeof(pStringW[0]) );wprintf(L"轉(zhuǎn)換后:%s\n",pStringW);ZeroMemory(pStringA,sizeof(pStringA)/sizeof(pStringA[0]));WideCharToMultiByte(CP_ACP,0,pStringW,wcslen(pStringW),pStringA,sizeof(pStringA)/sizeof(pStringA[0]),"",NULL);printf("轉(zhuǎn)換回來后:%s\n",pStringA);printf("printf輸出UNICODE:%S\n",pStringW);wprintf(L"wprintf輸出MBCS:%S\n",pStringA);ZeroMemory(pStringW,sizeof(pStringW)/sizeof(pStringW[0]));mbstowcs(pStringW,pStringA,_mbslen((const unsigned char*)pStringA));wprintf(L"mbstowcs轉(zhuǎn)換后:%s\n",pStringW);ZeroMemory(pStringA,sizeof(pStringA)/sizeof(pStringA[0]));wcstombs(pStringA,pStringW,sizeof(pStringW)/sizeof(pStringW[0]));printf("wcstombs轉(zhuǎn)換后:%s\n",pStringA);_tsystem(_T("PAUSE"));return 0; }其它常用字符串轉(zhuǎn)換
?UTF-8轉(zhuǎn)換到UNICODE再轉(zhuǎn)換到GBK的過程 #include <tchar.h> #include <windows.h> #include <stdio.h> #include <locale.h>int _tmain() {_tsetlocale(LC_ALL,_T("chs"));//取得UTF-8的編碼信息CPINFOEX ci = {};GetCPInfoEx(CP_UTF8,0,&ci);_tprintf(_T("Code Page Name: UTF-8\tMax Char Size:%uBytes\tDefault Char:0x%X%X\tLead Byte:0x%X%X%X%X%X%X%X%X%X%X%X%X\n"),ci.MaxCharSize,ci.DefaultChar[0],ci.DefaultChar[1],ci.LeadByte[0],ci.LeadByte[1],ci.LeadByte[2],ci.LeadByte[3],ci.LeadByte[4],ci.LeadByte[5],ci.LeadByte[6],ci.LeadByte[7],ci.LeadByte[8],ci.LeadByte[9],ci.LeadByte[10],ci.LeadByte[11]);_tprintf(_T("Unicode Default Char:%c\tCode Page:%u\tCode Page Name:%s\n"),ci.UnicodeDefaultChar,ci.CodePage,ci.CodePageName);//UTF-8編碼的串"1234ABCxyz趙錢孫李"UCHAR pUTF8[] = "\x31\x32\x33\x34\x41\x42\x43\x78\x79\x7A\xE8\xB5\xB5\xE9\x92\xB1\xE5\xAD\x99\xE6\x9D\x8E";//UTF-8轉(zhuǎn)UNICODEINT iLen = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pUTF8, -1, NULL,0);WCHAR * pwUtf8 = (WCHAR*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(iLen+1)*sizeof(WCHAR));//CP_UTF8指定原串的代碼頁MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pUTF8, -1, pwUtf8, iLen);wprintf(L"UTF8->Unicode = %s\n",pwUtf8);//UNICODE轉(zhuǎn)ANSI,經(jīng)過兩次轉(zhuǎn)換 UTF-8 已經(jīng)變成了 GBK 編碼iLen = WideCharToMultiByte(CP_ACP, 0, pwUtf8, -1, NULL, 0, NULL, NULL); CHAR* psGBK = (CHAR*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,iLen * sizeof(CHAR));WideCharToMultiByte (CP_ACP, 0, pwUtf8, -1, psGBK, iLen, NULL,NULL);printf("Unicode->GBK = %s\n",psGBK);HeapFree(GetProcessHeap(),0,pwUtf8);HeapFree(GetProcessHeap(),0,psGBK);_tsystem(_T("PAUSE"));return 0; }安全字符串函數(shù)示例
?#include <tchar.h>
#include <windows.h>
#include <strsafe.h>
#include <stdio.h>
#include <locale.h>int _tmain()
{_tsetlocale(LC_ALL,_T("chs"));const size_t szBuflen = 1024;TCHAR pAnyStr[] = _T("123ABCabc趙錢孫李");TCHAR pBuff[szBuflen];size_t szLen = 0;StringCchPrintf(pBuff,szBuflen,_T("WriteConsole OutPut:%s\n"),pAnyStr);StringCchLength(pBuff,szBuflen,&szLen);WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),pBuff,szLen,NULL,NULL);ZeroMemory(pBuff,szBuflen*sizeof(TCHAR));_tcscpy_s(pBuff,szBuflen,pAnyStr);_tprintf_s(_T("_tprintf_s OutPut:%s\n"),pBuff);_tsystem(_T("PAUSE"));return 0;
}
ATL庫中字符串轉(zhuǎn)換的支持
#include <tchar.h> #include <windows.h> #include <atlconv.h> #include <stdio.h> #include <locale.h>int _tmain() {_tsetlocale(LC_ALL,_T("chs"));USES_CONVERSION;WCHAR wStr[] = L"趙錢孫李123ABCxyz";wprintf(L"UNICODE Str = %s\n",wStr);printf("W2A Convert = %s\n",W2A(wStr));_tprintf(_T("W2T Convert = %s\n"),W2T(wStr));CHAR aStr[] = "123ABCxyz趙錢孫李";printf("MBCS Str = %s\n",aStr);wprintf(L"A2W Convert = %s\n",A2W(aStr));_tprintf(_T("A2T Convert = %s\n"),A2T(aStr)); _tsystem(_T("PAUSE"));}?作者:locojyw
email:locojyw@outlook.com
歡迎大家交流,現(xiàn)在學(xué)習(xí)windows核心編程,有什么錯(cuò)誤請(qǐng)指出
轉(zhuǎn)載注明出處
參考:
getcpinfo 頭文件 谷歌
總結(jié)
以上是生活随笔為你收集整理的UINCODE字符串和安全字符串函数(好)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高三物理教学工作计划
- 下一篇: 2020山东计算机大赛裴鹏飞,裴鹏飞个人