<一>什么是寬字符與窄字符
(1) 一個ANSI字符占一個字節共8位,一個UNICODE字符占兩個字節共16位;ANSI字符串以’\0’結束,0x00。
#Q: UNICODE字符串以什么結束??
#A: UNICODE字符串以L”\0”結束,0x0000。
(2)UNICODE和ANSI字符的相關定義及應用在各種運行庫中的體現如下:
1) 在C標准庫中
i. UNICODE在C標准庫下編譯的宏定義為_UNICODE
ii. 寬字符的數據類型為wchar_t,窄字符的數據類型為char。數據類型的定義在頭文件string.h中,對wchar_t的定義為:
{{{
typedef unsigned short wchar_t;
}}}
iii. 在頭文件string.h中,定義了分別對寬字符和窄字符的操作函數,如wcscpy和strcpy等。對寬字符的操作函數和對窄字符的操作函數的對照見:
http://blog.csdn.net/typecool/article/details/5877458
iv. 而在頭文件tchar.h中,定義了tchar宏,該文件模塊功能實現了”雙重功能”。
即例如_tcscpy方法宏,當編譯環境定義了UNICODE宏,則此方法宏為wcscpy,不然則為strcpy。等等。。。。
v. #Q: 對於對寬字符和窄字符的處理函數帶后綴_s,如wcscpy_s,strcpy_s,此類方法與wcscpy和strcpy等的區別在哪里?
#A: http://technet.microsoft.com/zh-cn/subscriptions/td1esda9(v=vs.80).aspx
wcscpy_s方法定義如下:
{{{
errno_t wcscpy_s(
wchar_t *strDestination,
size_t sizeInWords,
const wchar_t *strSource
);
}}}
wcscpy方法定義如下:
{{{
wchar_t* wcscpy_s(
wchar_t *strDestination,
const wchar_t *strSource
);
}}}
wcscpy_s方法多了一項參數size_t sizeInWords,即要拷貝的字符的個數。這樣就可避免strDestination空間分配不足。
2) 在windows中
i. UNICODE在windows下編譯的宏定義為UNICODE
ii.
3) 在C++標准庫中
4) 在MFC中
<二>寬字符與窄字符之間的轉換
有wcsXXX的函數專門處理寬字節的,就是strXXX一樣好使。呵呵,我不再懼怕了,就試着自己寫了一下,還是學了蠻多東西的:
1.有wcsXXX的函數和strXXX的函數對應處理寬字節,wcslen就是求長度的,wcscmp就是比較兩個字符串的。
2. 輸出也有相關的操作,wprintf(L”%s%s”);這樣的操作,對文件也可以用fwprintf函數來輸出。不過我發現貌似cout << wchar;不成功。也發現了一個問題,就是我輸出”相等”這樣一個字符串的時候,發現居然輸出不正確,無論是控制台和文件都有錯誤。可見,這個還是有點 小問題的。輸出其他的例如”12345”等都是正常的。哎,這個函數並不可靠啊。
3.寬字節和普通串的轉換問題,學了兩個函數,一個是:
wcstombs(char* strDes, const wchar*, size_t nMax);這個函數的作用是把wchar轉換為char。
char* strDes 為保存轉換后的普通字符串,wchar* 要被轉換的寬字符串。轉換的最大長度。這里的長度是轉換的個數,而不是字節長度。
mbstowcs() 就是一個相反的過程了,參數就不說了。
另一套轉換的函數是:
int WideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
LPSTR lpMultiByteStr,
int cbMultiByte,
LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar
);
他的參數很多,上面的連接有介紹,這里就不怎么細說了。
第 一個是編碼的方式,我一般用CP_ACP。第二個是轉換標志,MSDN上說什么都不設置更快,然后我就什么都不管了就用NULL了。具體作用不知道,等遇 到了再學。第三個參數就是被轉換的字符串,第四個參數是該字符串的長度,-1表示自動算長度,如果是手動給出,一定要把最后的終結符長度也算上。我覺得還 是-1來的實際。第五個參數就是保存轉換串的指針,第六個參數就是保存串的長度,這里是單位字符的個數。如果轉換的時候沒有終結符,那么結果也沒有終結 符,要注意下。最后兩個參數就是默認的填充字符和是否使用了默認填充字符,我一般就用NULL代替。
普通串轉寬字節也是類似。
這 里有幾個注意的,一定要保證空間足夠。還有就是那個長度是單位字符個數,而不是字節數,在轉換時,推薦被轉換的字符串長度設置為-1,因為這樣他會自動算 出終結符結束。返回值也是轉換的單位字符個數。例如”相等”有普通串轉換為寬字節串,返回結果是3,(有終結符),而反過來就是5。如果返回時0 說明轉換失敗。
心得:雖然WideCharToMultiByte的參數要多,感覺用的沒有wcstombs爽,可是他的准確好高一些, 要轉換的話,還用用WideCharToMultiByte比較合適,還有就是雖然有一套wcsXXX的庫函數,可惜輸出還是出現問題的。如果全都用寬字 節,那沒有關系wcsxxx的函數還是蠻好用的。還有一個疑惑我明明查字典multi是多的意思也就是說multibyte是多字節,我的中文版 VS2005配置里面也是說的多字節。搞不懂為什么要用寬字節呢?可能是多字節編碼不好用吧。呵呵。 廢話也說完了,奉上源代碼:
int main() { FILE* fp ; WCHAR wchar[5] = L"相等相等"; //定義一個寬字節的變量,初始為"相等" fp = fopen("1.txt", "w+"); //打開文件稱奧做 fwprintf(fp, L"%s\n", wchar); //輸出到文件 fclose(fp); //關閉文件 WCHAR wc2[5]; //定義第二個寬字節變量 //wc開始的有很多寬字節的操作。都和str相對應。 wcscpy(wc2, wchar); //復制。 int n = wcscmp(wc2, wchar); //比較 if (n == 0) { wprintf(L"相等\n"); //這里是否注意到沒有wprintf有問題的。 } char str[10]; //定義char字符。 n = wcstombs(str, wc2, 9); //寬字節轉換為muiltychar printf("%s\n", str); //輸出結果 for (int i = 0; i < 5; ++i) { wc2[i] = L'1' + i; } wc2[4] = 0; n = wcstombs(str, wc2, 9); //寬字節轉換為muiltychar printf("%s\n", str); //輸出結果 //另外的方式轉換 n = WideCharToMultiByte(CP_ACP, NULL, wchar, wcslen(wchar) + 1, str, 10, 0, 0); printf("%s\n", str); char str2[10] = "加一"; WCHAR wc3[10]; n = MultiByteToWideChar(CP_ACP, NULL, str2, strlen(str2) + 1, wc3, 10); //char到寬字節。 system("pause"); return 0; }
