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();