UINCODE字符串和安全字符串函数(好)
[原]UINCODE字符串和安全字符串函數
字符集基礎知識
在計算機中,字符都是以二進制編碼方式存在于存儲中
編碼與解碼
將字符輸入計算機存儲的過程類似于一個”編碼”的過程
而將對應的”編碼”顯示出來的過程類似于一個解碼的過程
?
二進制值本身代表什么含義是可以隨意定義的,在內存中用某個2進制的值代表某一個值,
比如說用8位2進制的代表單字節這些,16位,32位等等
用某個二進制值表示某個字符完全是人為設定的,最終字符集就是字符到其二進制數字值得映射
?
單字節字符集(SBCS) ?Single Byte Character Set
單字節字符集使用一個字節(8Bits)編碼字符
最大可編碼256個字符
有名的單字節字符集就是ASCII碼
字符集的變體稱為代碼頁,主要包括不同的特殊字符,一般為一種語言或語言組定制
用在美國的OEM代碼頁標識符是437
調用GetACP函數可以檢索系統中ANSI代碼頁標識符
使用GetOEMCP可以得到OEM代碼頁標識符
OemToChar和OemToCharBuff函數可以把字符或串從OEM頁轉到ANSI代碼頁
反之用CharToOem或CharToOemBuff
GetCpInfo函數可以得到代碼頁中的詳細信息:最大字符大小、缺省字符、前置符(詳見CPINFO結構體)
使用MultiByteToWideChar可以把單字節字符或串轉換到UNICODE反之用WideCharToMultiByte
雙字節字符集(DBCS)?Double Byte Character Set
雙字節字符集被稱作擴展的8Bits字符集,最小單位仍是一個字節
Windows亞洲語言版中一般都支持ANSI字符集和DBCS
在這些平臺的程序中需要特別的算法處理DBCS
使用IsDBCSLeadByte可以判定所給字符是否是雙字節字符的第一個字節
使用MultiByteToWideChar可以將雙字節字符或串轉換為UNICODE
反之使用WideCharToMultiByte
有些字符集編碼甚至使用4Bytes表示一個字符,此時統稱為多字節字符集MBCS(MultiBytes Char Set)
常用字符集和字符編碼
ASCII字符集
GB2312字符集(國標碼)
GB18030字符集
Unicode字符集
?
ASCII字符集
ASCII(AmericanStandard Code for Information Interchange,美國信息交換標準代碼)
是基于拉丁字母的一套字符編碼
主要用于顯示現代英語,而其擴展版本EASCII則可以勉強顯示其他西歐語言。它是現今最通用的單字節編碼系統
等同于國際標準ISO/IEC 646
將ASCII字符集轉換為計算機可以接受的數字系統的數的規則。使用7位(bits)表示一個字符,共128字符;
為了表示更多的歐洲常用字符對ASCII進行了擴展,ASCII擴展字符集使用8位(bits)表示一個字符,共256字符。
ASCII的最大缺點是只能顯示26個基本拉丁字母、阿拉伯數目字和英式標點符號,因此只能用于顯示現代美國英語(而且在處理英語當中的外來詞如na?ve、café、élite等等時,所有重音符號都不得不去掉,即使這樣做會違反拼寫規則)。
而EASCII雖然解決了部份西歐語言的顯示問題,但對更多其他語言依然無能為力。
GBXXXX字符集 (國標字符集)
因ASCII碼的限制,為了顯示中文,必須設計一套編碼規則用于將漢字轉換為計算機可以接受的數字系統的數。
為此規定那些127號之后的奇異符號(即EASCII)取消掉,同時規定:一個小于127的字符的意義與原來相同,但兩個大于127的字符連在一起時,就表示一個漢字,前面的一個字節(他稱之為高字節)從0xA1用到 0xF7,后面一個字節(低字節)從0xA1到0xFE,這樣可以組合出大約7000多個簡體漢字
上述規則即為GB2312中國國家標準簡體中文字符集GBO
對于人名、古漢語等方面出現的罕用字,GB2312不能處理,這導致了后來GBK及GB 18030漢字字符集的出現
GB18030字符集
國家標準GB 18030-2005《信息技術 中文編碼字符集》
與GB 2312-1980完全兼容,與GBK基本兼容,支持GB 13000及Unicode的全部統一漢字,共收錄漢字70244個
特點:
n? 與UTF-8相同,采用多字節編碼,每個字可以由1個、2個或4個字節組成。
n? 編碼空間龐大,最多可定義161萬個字符。
n? 支持中國國內少數民族的文字,不需要動用造字區。
n? 漢字收錄范圍包含繁體漢字以及日韓漢字
Unicode字符集
當計算機傳到世界各個國家時,為了適合當地語言設計和實現很多不同的編碼方案。
在本地使用沒有問題,一旦出現在網絡中,由于不兼容,互相訪問就出現了亂碼現象。
為了解決這個問題,一個偉大的創想產生了——Unicode
UNICODE標準前身是通用字符集(Universal Character Set)UCS
現在標準由UNICODE聯盟維護,官方網址:www.unicode.org 目前最新的標準版本是7.0 ?(2015.01.16)
最初的UNICODE使用兩個字節編碼字符集, 現在已被新的編碼方式取代
Windows支持UNICODE字符集及全部編碼方式
UNICODE詳解
Unicode是國際組織制定的可以容納世界上所有文字和符號的字符編碼方案。
Unicode用數字0-0x10FFFF來映射這些字符,最多可以容納1114112個字符,或者說有1114112個碼位。
碼位就是可以分配給字符的數字。UTF-8、UTF-16、UTF-32都是將數字轉換到程序數據的編碼方案。
通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或稱ISO/IEC 10646)標準所定義的標準字符集。UCS-2用兩個字節編碼,UCS-4用4個字節編碼。
現在UCS和UNICODE基本合二為一?
與其它的直接指定式編碼字符集不同,UNICODE是字符集,UTF-x是編碼方式
一般情況下:一個字符對應到一些位(bits). 如: A -> 0100 0001
而在 Unicode 中, 一個字符實際上對應一種叫做 code point 的東西。
每一個字母表中的抽象的字母,都被賦予了一個數字,比如 U+0645. 這個叫做 code point.
U+ 表示: Unicode, 數字是 16 進制的。
Unicode 中 code point 的數字的大小是沒有限制的,而且也早就超過了 65535. 所以不是每個字符都能存儲在兩個字節中。
運行CharMap程序可以查看U+形式的字符詳細信息?CMD
使用UNICODE的好處
Windows從NT內核版本開始所有平臺均完全基于UNICODE打造
使用UNICODE版API節約了字符轉換的額外開銷,從根本上保證了程序能夠最高效的利用API的性能
UNICODE函數不再考慮因字符不同而帶來的字符串長不確定的問題(這曾是程序員的噩夢)
UNICODE編碼的標準唯一性使得UNICODE具有非常好的可移植性
允許同時顯示不同國家的不同語言的字符在一個程序中
Windows API 與 UNICODE
Windows平臺提供3種關于字符操作相關API的封裝形式
n? 一般宏定義形式API(兼容UNICODE和非UNICODE)
n? 以A結尾的非UNICODE版API
n? 以W結尾的UNICODE版API
Windows內部其實僅提供了UNICODE版的API,非UNICODE版的API在內部先將參數轉換成UNICODE串,然后再調用UNICODE版的API,如果返回結果仍然是UNICODE,那么就再進行反向轉換
兼容版的API在編譯時,如果指定了UNICODE宏,那么就替換成UNICODE版的API否則就替換成非UNICODE版的API
由此可見調用非UNICODE版的API會付出額外的代價,當字符串較長,或者調用較多時,性能損失還是比較明顯的
綜上本課程提倡使用兼容版API宏定義,并且使用UNICODE宏和_UNICODE宏編譯VC代碼
VC中默認采用的是UTF-16編碼方式,因此一個UNICODE字符占用2字節
VC中非UNICODE的串統稱為MBCS(多字節字符集)
?
Windows平臺的UNICODE串函數(API)
strlen函數返回字符串中的字節數,而lstrlen返回字符數,不管字符是1字節還是2字節
與標準C庫函數tolower或toupper不同,CharLower或CharUpper可以作用于字符集中的任何字符(包括非英文字符等,比如?和?)
wsprintf和wvsprintf是標準C函數sprintf和vsprintf的擴展(API)
也是僅有的兩個支持格式說明的UNICODE版函數
?
系統本地語言支持(National Language Support)
系統本地標示符,是一個語言/子語言標示符和結合到一個雙字值中的保留字
通過該標示符,應用程序可以進一步得到系統安裝的語言版本,系統區域設置等信息(比如中文版Windows,時區是東8區)
通過調用GetSystemDefaultLCID和GetUserDefaultLCID函數可以獲得區域信息標識符
要獲得本地語言標識符可以調用GetSystemDefaultLangID和GetUserDefaultLangID
得到區域信息有助于調用一些與區域信息相關的API:比如獲取日期時間格式、貨幣格式等
這些是一些高級國際化軟件必需要使用的信息
關于這組函數的調用,將在需要調用時進行介紹
如何正確使用兼容版字符集編程
???????? 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標準庫字符串函數時的幾個問題
如果不調用setlocale方法,標準庫函數對串的字符集解釋可能不正確而輸出亂碼(TCHAR版:_tsetlocale)
對于含有非ASCII碼的串,調用strlen時返回的是字符串的字節長度,而不是字符數(因為有些字符是多個字節,因此字節數不等于字符數)
使用MBCS版的庫函數就可以正確偵測到含有多字節字符的串中的字符數
即使使用UNICODE和_UNICODE宏(或MBCS和_MBCS)編譯的項目代碼,仍然可以使用非UNICODE版或純UNICODE版的函數,這個宏其實僅對TCHAR.h中和Windows.h中的宏定義起作用,對原函數無任何影響(對Windows API也成立)
字符集的轉換
有些情況下,需要在各種不同的字符集之間轉換字符串,甚至需要在不同的編碼方式間進行轉換
此時可以調用C庫函數mbstowcs或wcstombs等進行轉換
或者可以用Windows API:MultiByteToWideChar或WideCharToMultiByte進行相互轉換
利用OemToChar可以將一個OEM版字符串轉換成ANSI串或寬字節字符串,反之用CharToOem
傳統C庫函數的一些安全問題
在微軟產品的安全漏洞中,有很大一部分是由于使用C標準庫(C Runtime Library)的函數,特別是有關字符串處理的函數導致的;(數組下標越界)
多數是因為緩沖區溢出導致執行惡意代碼,從而提升了權限,進而進行惡意攻擊;
這一點并不奇怪,因為C標準庫函數的設計大約是30年前的事情了;當時并沒有太多安全方面的考慮;
在http://msdn.microsoft.com/en-us/library/bb288454.aspx有一個完整的不安全C庫函數的列表
從VS2005起,如果C/C++代碼中使用了這些函數,編譯器都會提示一個C4996的不安全函數引用警告
非服務端軟件可以關閉或直接忽略這個警告
安全字符串函數
作為非安全字符串的替代,可以在VS2005(及以上版本中)調用兩組安全的字符串操作函數:
StringSafe Functions(微軟提供的內聯形式函數,可以當做API)
SafeCRT(C庫函數)
其它的一些安全函數替代品
一般使用帶有_s結尾的新版C庫函數,替代原有的C庫函數,如:用fopen_s替代fopen或wfopen_s替代wfopen等
如果是Windows平臺的程序,可用類似功能的API替代C庫函數,如:用CreateFile代替fopen,wfopen等;
要使用String Safe函數,只需包含strsafe.h即可
使用Safe CRT函數,需查看MSDN以確定需要包含的頭文件
使用安全字符串函數的一些需考慮問題
StringSafe 函數因為使用的是內聯方式,因此可以直接使用,并具備一定的平臺無關性(推薦使用)
Safe CRT是正在考察的標準庫函數,因此不同編譯環境中細節上可能還有差異(詳情見相應環境的幫助文檔)
對于客戶端軟件或單機軟件可以不考慮使用安全字符串函數,仍可使用傳統的C庫函數或C++字符串類
在安全性要求較高的環境中,比如服務端軟件中,盡力避免使用stl中的string類或MFC/ATL中的CString類,需要使用時考慮使用安全字符串操作函數自行封裝,同時避免使用非安全的庫函數(Windows平臺上的網絡服務應用尤其要避免使用非安全的字符串函數或字符串類)
安全字符串函數因具備緩沖區安全檢測機制,所以有一定性能損失,但損失不大可以忽略(詳細情況可以使用VS2008自帶性能分析工具進行分析比較)
ATL庫中字符串轉換的支持
ATL庫中的字符串轉換通過宏定義在頭文件atlconv.h中
此頭文件可以單獨使用,不需要其它的ATL組件或頭文件支持
使用時需要先調用一個宏USES_CONVERSION;然后就可以調用A2T,A2W,W2T,W2A等宏進行字符串轉換
?
?
?
示例
UNICODE版API調用示例
#include <tchar.h> #include <windows.h> #include <locale.h> #include <malloc.h>int _tmain() {_tsetlocale(LC_ALL,_T("chs"));//大小寫轉換 針對多字節字符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("一二三趙錢孫李ABCabc1231234");//字符長度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; }系統本地語言支持(查看本地的語言的示例)
#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; }調用C庫函數的例子
#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; }字符集轉換示例
?
#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("轉換前:%s\n",pStringA);wchar_t pStringW[256] = {};MultiByteToWideChar( CP_ACP, 0, pStringA,strlen(pStringA)+1, pStringW, sizeof(pStringW)/sizeof(pStringW[0]) );wprintf(L"轉換后:%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("轉換回來后:%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轉換后:%s\n",pStringW);ZeroMemory(pStringA,sizeof(pStringA)/sizeof(pStringA[0]));wcstombs(pStringA,pStringW,sizeof(pStringW)/sizeof(pStringW[0]));printf("wcstombs轉換后:%s\n",pStringA);_tsystem(_T("PAUSE"));return 0; }其它常用字符串轉換
?UTF-8轉換到UNICODE再轉換到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轉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轉ANSI,經過兩次轉換 UTF-8 已經變成了 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; }安全字符串函數示例
?#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庫中字符串轉換的支持
#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
歡迎大家交流,現在學習windows核心編程,有什么錯誤請指出
轉載注明出處
參考:
getcpinfo 頭文件 谷歌
總結
以上是生活随笔為你收集整理的UINCODE字符串和安全字符串函数(好)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高三物理教学工作计划
- 下一篇: 2020山东计算机大赛裴鹏飞,裴鹏飞个人