字符串有好幾種不同的類型,新手一開始學(xué)的一定是char,這種是最基礎(chǔ)的字符串,用ASCII碼來表示英文,這個(gè)叫做ANSI編碼。現(xiàn)在新寫程序都應(yīng)當(dāng)使用寬字符,類型是wchar_t,一個(gè)wchar_t占兩個(gè)字節(jié),不管英文還是中文,這種編碼是一種Unicode編碼,Unicode編碼的程序即使拿到其他語(yǔ)言的系統(tǒng)上運(yùn)行也能正確顯示,前提是那個(gè)系統(tǒng)安裝了中文字體。還有一種是MBCS,翻譯成中文就是多字節(jié)字符串,一個(gè)字符有多個(gè)字節(jié)組成,不一定是2字節(jié)也可以多余兩字節(jié),GB2312,UTF8等都屬此類。
編譯器是不能自動(dòng)轉(zhuǎn)換char和wchar_t的,因?yàn)樗麄冎g的轉(zhuǎn)換必須要指定代碼頁(yè)。 微軟提供了一系列的函數(shù)來對(duì)應(yīng)操作這些字符串,你只要在msdn搜一個(gè)strlen,他下面會(huì)列出比如wstrlen,w開頭的用來操作wchar_t,mb開通的用來操作MBCS等。 值得一提的是一組_t開頭的,這是一種“自適應(yīng)”的函數(shù),在Visual Studio的工程選項(xiàng)里面可以選擇應(yīng)用程序編碼使用Unicode還是普通的,那么這個(gè)_t就會(huì)自動(dòng)適應(yīng)這個(gè)選項(xiàng),比如_tcslen在選項(xiàng)為Unicode的時(shí)候自動(dòng)執(zhí)行wstrlen,在選項(xiàng)為ANSI編碼的時(shí)候執(zhí)行strlen。 再說一下Windows API有關(guān)字符串類型的定義,常見的有這么幾個(gè) #define LPSTR char* #define LPCSTR const char* #define LPTSTR TCHAR* #define LPCTSTR const TCHAR* #define LPWSTR wchar_t* #define LPCWSTR const wchar_t* 你仔細(xì)看一下就找到了規(guī)律,LP是指針,微軟的傳統(tǒng),STR表示字符串,C表示const,T表示TCHAR,W表示wchar_t。 最后說一下TCHAR,TCHAR和前面說的_tcslen有一樣的作用,他是這么定義的 #ifdef _UNICODE #define TCHAR wchar_t #else #define TCHAR char #endif 也就是根據(jù)編譯器的自動(dòng)適應(yīng)。 最后很重要的一點(diǎn)是你在程序里面怎么表示char和wchar_t的字符串。 最熟悉的就是拿引號(hào)包括在字符串兩邊,這樣表示這個(gè)字符串是char類型的: LPCSTR sz = "Some characters"; 這個(gè)是不能付給需要wchar_t的地方的,比如你寫wprintf(sz)就是錯(cuò)的,編譯器會(huì)報(bào)錯(cuò)不能從const char*轉(zhuǎn)成const wchar_t*。寫寬字符字符串必須在引號(hào)前加一個(gè)L,如 LPCWSTR szw = L"Wide characters"; 這樣wprintf(szw)就正確了。 為了自適應(yīng)TCHAR的需要,微軟有定義了一個(gè)宏,_T,這個(gè)宏包括在字符串的變 LPCTSTR tsz = _T("adaptive characters"); 這樣的字符串會(huì)根據(jù)編譯器的選項(xiàng)自動(dòng)加L或者不加。 然后那些函數(shù)里面的n,比如strncpy還有類似的后面帶_s的,strcpy_s,這又是完全另外一個(gè)問題。原因是原始的C語(yǔ)言庫(kù)比如strcpy很容易導(dǎo)致緩沖區(qū)溢出,你很容易寫出這樣的語(yǔ)句 char sz[5]; strcpy(sz, "something to copy"); 這個(gè)語(yǔ)句完全通過編譯,但是他有嚴(yán)重的問題,sz的長(zhǎng)度不足以復(fù)制那整個(gè)字符串,而strcpy卻不知道,因此它就會(huì)試圖去修改超過緩沖區(qū)的內(nèi)容,導(dǎo)致緩沖區(qū)溢出,緩沖區(qū)溢出是很廣泛的漏洞,原始的C語(yǔ)言庫(kù)無(wú)法避免的這問題,有時(shí)候你接受用戶的輸入,你沒法知道用戶會(huì)輸入多少數(shù)據(jù)。 因?yàn)楝F(xiàn)在有了strncpy, strcpy_s以及比如scanf_s, gets_s等幾乎所有的標(biāo)準(zhǔn)庫(kù)函數(shù)都帶了一個(gè)或多個(gè)變形的版本,這些版本基本就只多了一個(gè)參數(shù),就是你給這個(gè)函數(shù)的緩沖區(qū)大小。比如剛才的例子: strcpy_s(sz, 5, "ssdfsfdsfsf"); 這個(gè)代碼在Debug版本運(yùn)行的時(shí)候就會(huì)跳出Runtime Error告訴你Buffer to small,在Release版本不會(huì)跳錯(cuò),但是它會(huì)截?cái)嗄阋獜?fù)制的字符串到緩沖區(qū)的大小,保證不會(huì)發(fā)生緩沖區(qū)溢出。 新編寫嚴(yán)肅的程序都應(yīng)當(dāng)使用安全版本的函數(shù),s可以理解是safety的縮寫?,F(xiàn)在微軟的編譯器在你使用strcpy這樣不安全的函數(shù)的時(shí)候會(huì)提出警告。 帶l的函數(shù)就是可以設(shè)置一個(gè)字符語(yǔ)言的區(qū)域,沒有l(wèi)的函數(shù)就是使用操作系統(tǒng)默認(rèn)的語(yǔ)言設(shè)置。 |
|