MFC中對字串的定義大多是使用CString類,不可避免的有時候需要將CString類型的字串轉換為整形或者其他類型的變數。最近在做的一個項目中就遇到了這樣的問題。
用CString定義了一個由數字組成的字串str,但是需要將其轉換為BYTE型使用。很容易就想到了atoi函數,atoi函數主要功能是將一個字串轉化為整型數,函數原型如下:
[code]int atoi(const char * string ); [/code]
可以看到函數的參數是const char *,經測試在vC 6.0環境下直接轉換是沒有任何問題的。
[code]int n = atoi(str) [/code]
但是同樣的代碼在VS2008環境下會報錯,提示w_char*不能轉為_char*。因為建立工程的時候我勾選了unicode編碼。
原因分析:
在Visual C++ NET環境下,預設的字元集形式是Unicode,但在VC6.0環境下,預設的字元集形式是多位元組字元集(MBCS,Multi-Byte Character Set),這就導致了在VC6.0中非常簡單實用的各類字元操作和函數在VS環境下運行時會出現各種各樣的錯誤。以下給出了VS環境Unicode字元集下CString和char *之間的相互轉換方法,也即Unicode字元集和MBCS字元集的轉換
- Unicode下CString轉換為char *
(1)使用windows API:WideCharToMultiByte進行轉換
從函數名就可以看出該函數的功能,將unicode編碼的widechar轉換為多位元組字元,查閱msdn,其定義如下:[code]int WideCharToMultiByte(UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
LPSTR lpMultiByteStr,
int cbMultiByte,
LPCSTR lpDefaultChar,
LPBOOL lpUsedDefaultChar
);
[/code]
第三個參數lpWideCharStr是待轉換的寬字元串,第四個參數cchWideChar表示待轉換字串的長度,第五個參數lpMultiByteStr表示轉換為的多位元組字串指標,第六個參數cbMuliByte表示轉換為的多位元組字串的長度(位元組長度)。函數的傳回值描述如下:Returns the number of bytes written to the buffer pointed to by
lpMultiByteStr if successful;If the function succeeds and cbMultiByte is 0, the return value is the required size, in bytes, for the buffer indicated by
lpMultiByteStr. The function returns 0 if it does not succeed. 以下樣本來自網路。
[code]CString str = _T("("D:\校內項目\QQ.bmp")
int n = str.GetLength(); // n = 14, n是按字元擷取字串長度,中文字元和英文字元均算作一個字元。
//擷取多位元組字串長度,按位元組計數,中文字元佔兩位元組
Int len = WideCharToMultiByte(CP_ACP, 0, str, str.GetLength(), NULL, 0, NULL, NULL) //針對上例len=18,因為中文字元佔2位元組
//為多位元組字元申請空間,數組大小為按位元組計算的字串長度,注意字串還需要\0結尾
Char * p = new char[len +1]
//寬字元串轉換為多位元組編碼的字串
WideCharToMultiByte(CP_ACP, 0, str, str.GetLength(), p, len, NULL, NULL);
P[len+1] = '\0'; //<strong>字串以\0結尾 應該是存到p[len]而不是len+1 </strong>[/code]
(2)使用宏T2A或者W2A
代碼如下:
[code]
CString str = _T("("D:\校內項目\QQ.bmp");
//宣告身份識別符,這個不能忘記,否則編譯器會報錯
USES-CONVERSION;
//調用函數,T2A和W2A均支援ATL和MFC中的字元轉換
char * p = T2A(str);
//char * p = W2A(str); //也可實現轉換
[/code]
注意: 有時候可能還需要添加引用#include <afxpriv.h> //原文抄過來了,我沒遇到過
- unicode下char *轉換為CString
(1)使用API:MultiByteToWideChar進行轉換
MultiByteToWideChar用於將多位元組字串轉換為unicode環境下的寬字元。msdn中定義如下:
[code]
int MultiByteToWideChar(UINT CodePage,DWORD dwFlags,
LPCSTR lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar,
);
[/code]
實現代碼如下:
[code]
char * p = "D:\校內項目\QQ.bmp";
//計算char *數組大小,以位元組為單位,一個漢字佔兩個位元組
int charLen = strlen(p);
//計算多位元組字元的大小,按字元計算。
int len = MultiByteToWideChar(CP_ACP,0,p,charLen,NULL,0);
//為寬位元組字元數組申請空間,數組大小為按位元組計算的多位元組字元大小
TCHAR *buf = new TCHAR[len + 1];
//多位元組編碼轉換成寬位元組編碼
MultiByteToWideChar(CP_ACP,0,p,charLen,buf,len);
buf[len] = '\0'; //添加字串結尾,注意不是len+1
//將TCHAR數群組轉換為CString
CString pWideChar;
pWideChar.Append(buf);
//刪除緩衝區
delete []buf;
[/code]
(2)使用宏A2T或者W2A進行轉換
代碼如下:
[code]
char * pF = "D:\校內項目\QQ.bmp";
USES_CONVERSION;
CString s = A2T(p);
//CString s = A2W(p);
[/code]
(3) 使用_T宏,將字串轉換為寬字元
[code]
//多位元組字元集,在vc6和vc7種可以編譯通過的語句,但VS2005不能通過,預設為Unicode字元集
//AfxMessageBox("載入資料失敗",0);
//書寫代碼使用TEXT("")或_T(""),文本在UNICODE和非UNICODE程式裡都通用
AfxMessageBox(_T("載入資料失敗"),0);
//如果是只在Unicode環境下的話,也可以使用L宏
Str = L"載入資料失敗";
[/code]
- 總結
直接轉換在基於MBCS的工程中是可以的,但在基於unicode字元集的工程中行不通,CString會以unicode的形式儲存資料,強制轉換隻會返回第一個字元。
- 測試代碼:
char m_strIP[256] = "D:\\192.168.1.101";
int charLen = strlen(m_strIP);
int len = MultiByteToWideChar(CP_ACP,0,m_strIP,charLen,NULL,0);
TCHAR *buf = new TCHAR[len + 1];
MultiByteToWideChar(CP_ACP,0,m_strIP,charLen,buf,len);
buf[len] = '\0'; //添加字串結尾,注意不是len+1
CString pWideChar;
pWideChar.Append(buf);
delete []buf;//刪除緩衝區
CString CShead(_T("D:\\"));
CString CStemp(_T("\\"));
char m_strIP[256] = "192.168.1.101";
USES_CONVERSION;
CString S1= A2T(m_strIP);
S1 = CShead + S1;
CTime t = CTime::GetCurrentTime();
char dir[10];
char filename[20];
memset(dir,0,10);
memset(filename,0,20);
sprintf(dir,"%04d%02d%02d", t.GetYear(),t.GetMonth(), t.GetDay());
int h = t.GetHour();
int m = t.GetMinute();
int s = t.GetSecond();
sprintf(filename,"%02d%02d%02d-%02d%02d%02d.avi",h,m,s,h,m,s+2);
CString S2= A2T(dir);
S2 = S1 + CStemp + S2;
CString FilePath= A2T(filename);
FilePath = S2 + CStemp + FilePath;
int err;
if (!CreateDirectory(S1,NULL))
{
if (GetLastError() == ERROR_ALREADY_EXISTS )
{
cout<<"ALREADY_EXISTS"<<endl;
}
else
cout<<"error"<<endl;
}
if (!CreateDirectory(S2,NULL))
{
if (GetLastError() == ERROR_ALREADY_EXISTS )
{
cout<<"ALREADY_EXISTS"<<endl;
}
else
cout<<"error"<<endl;
}
CFile file(FilePath,CFile::modeCreate|CFile::modeReadWrite);
file.Write(m_strIP,strlen(m_strIP));
file.Close();