CString与LPCWSTR、LPWSTR等数据类型的转化
之前我遇到过类似的问题,在以前两篇博文中也提到过类似编码问题:
VC6.0设定UNICODE编译环境、VC中_T("")与L区别,但是都没有涉及到这些数据类型的转换。
1. CString与LPCWSTR的转换
LPCWSTR 是Unicode字符串常量指针,初始化时串有多大,申请空间就有多大,以后存储若超过则出现无法预料的结果,这是它与CString的不同之处。而CString是一个串类,内存空间类会自动管理。LPCWSTR的定义为:
- typedef CONST WCHAR *LPCWSTR, *PCWSTR;
LPCWSTR 初始化如下:
- LPCWSTR Name=L"TestlpCwstr";
- //方法一
- CString str=_T("TestStr");
- USES_CONVERSION;
- LPWSTR pwStr=new wchar_t[str.GetLength()+1];
- wcscpy(pwStr,T2W((LPCTSTR)str));
- // 方法二
- CString str=_T("TestStr");
- USES_CONVERSION;
- LPWCSTR pwcStr = A2CW((LPCSTR)str);
注意:
慎用USES_CONVERSION
USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。在ATL下使用要包含头文件#include <atlconv.h>
使用USES_CONVERSION一定要小心,它们从堆栈上分配内存,直到调用它的函数返回,该内存不会被释放。如果在一个循环中,这个宏被反复调用几万次,将不可避免的产生stackoverflow。
使用USES_CONVERSION一定要小心,它们从堆栈上分配内存,直到调用它的函数返回,该内存不会被释放。如果在一个循环中,这个宏被反复调用几万次,将不可避免的产生stackoverflow。
在一个函数的循环体中使用A2W等字符转换宏可能引起栈溢出。
- #include <atlconv.h>
- void fn()
- {
- while(true)
- {
- {
- USES_CONVERSION;
- DoSomething(A2W("SomeString"));
- }
- }
- }
- #define A2W(lpa) (\
- ((_lpa = lpa) == NULL) ? NULL : (\
- _convert = (lstrlenA(_lpa)+1),\
- ATLA2WHELPER((LPWSTR) alloca(_convert*2), _lpa, _convert)))
- #define ATLA2WHELPER AtlA2WHelper
- inline LPWSTR WINAPI AtlA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
- {
- ATLASSERT(lpa != NULL);
- ATLASSERT(lpw != NULL);
- // verify that no illegal character present
- // since lpw was allocated based on the size of lpa
- // don't worry about the number of chars
- lpw[0] = '\0';
- MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
- return lpw;
- }
分配的内存是在函数的栈中分配的。 而VC编译器默认的栈内存空间是2M。当在一个函数中循环调用它时就会不断的分配栈中的内存。那么为了避免这类问题的发生,我们应该把字符转换部分放到一个函数中处理,如下:
- void fn2()
- {
- USES_CONVERSION;
- DoSomething(A2W("SomeString"));
- }
- void fn()
- {
- while(true)
- {
- fn2();
- }
- }
以上说明是为了解释USES_CONVERSION
提供另一种快捷的方法CString中的一个方法
AllocSysString,它返回BSTR
- //方法三
- CString str = _T("test");
- LPCWSTR lpcwStr = str.AllocSysString();
- LPCWSTR pcwStr = L"TestpwcStr";
- CString str(pcwStr);
MFC中CString和LPSTR是可以通用,其中A2CW表示(LPCSTR) -> (LPCWSTR)
2. CString和LPWSTR的转换
我也看到CString和LPWSTR有这么转化的:
- CString str = _T("test");
- LPWSTR lpwStr = (LPWSTR)(LPCTSTR)str;
如果要获取str里面的内容,用ATL转换如下,也有其他转换方法:
- CString str = _T("test");
- USES_CONVERSION;
- LPWSTR lpwStr = A2W(str);
当然也可以用如下方法,所用函数wcscpy,宽字符复制函数:
- wchar_t szBuffer[100] = {0};
- wcscpy(szBuffer,L"test");
- LPWSTR lpwStr = szBuffer;
3. CString与LPSTR转换
CString转为LPSTR
- //方法一
- CString str = _T("test");
- LPSTR lpStr = str.GetBuffer();
- str.ReleaseBuffer();
- //方法二
- CString str = _T("test");
- LPSTR lpStr = (LPSTR)(LPCSTR)str;
这里比较简单,给出一种转换方法。
- LPSTR lpStr = L"lpTestStr";
- CString str(lpStr);
4. CString转为LPCSTR
CString转为LPCSTR可直接转换- CString str = _T("test");
- LPCSTR lpcStr = (LPCSTR)str;
5. CString转为char*
- //方法一
- CString str = _T("test");
- char *p = str.GetBuffer();
- //方法二
- CString str = _T("test");
- char *p = (LPSTR)(LPCSTR)str;
- char *p = "test";
- CString str = ("%s",p);
- char *p = "test";
- CString str;
- str.Format(_T("%s"),p);
6. CString转换成int、float等
直接使用 atoi,atof,atol等函数来实现。7. 其他类型
在头文件<atlconv.h>中定义了ATL提供的所有转换宏,如:
- A2CW (LPCSTR) -> (LPCWSTR)
- A2W (LPCSTR) -> (LPWSTR)
- W2CA (LPCWSTR) -> (LPCSTR)
- W2A (LPCWSTR) -> (LPSTR)
所有的宏如下表所示:
A2BSTR | OLE2A | T2A | W2A |
A2COLE | OLE2BSTR | T2BSTR | W2BSTR |
A2CT | OLE2CA | T2CA | W2CA |
A2CW | OLE2CT | T2COLE | W2COLE |
A2OLE | OLE2CW | T2CW | W2CT |
A2T | OLE2T | T2OLE | W2OLE |
A2W | OLE2W | T2W | W2T |
上表中的宏函数,非常的有规律,每个字母都有确切的含义如下:
2 | to 的发音和 2 一样,所以借用来表示“转换为、转换到”的含义。 |
A | ANSI 字符串,也就是 MBCS。 |
W、OLE | 宽字符串,也就是 UNICODE。 |
T | 中间类型T。如果定义了 _UNICODE,则T表示W;如果定义了 _MBCS,则T表示A |
C | const 的缩写 |
利用这些宏,可以快速的进行各种字符间的转换。使用前必须包含头文件,并且申明USER_CONVERSION;
使用 ATL 转换宏,由于不用释放临时空间,所以使用起来非常方便。
但是考虑到栈空间的尺寸(VC 默认2M),使用时要注意几点:
1、只适合于进行短字符串的转换;
2、不要试图在一个次数比较多的循环体内进行转换;
3、不要试图对字符型文件内容进行转换,因为文件尺寸一般情况下是比较大的;
4、对情况 2 和 3,要使用 MultiByteToWideChar() 和 WideCharToMultiByte();