很多网上的文章只讲了用法,但是没有真正深入地去讲CString转换为啥可以这样做
CString其实是一个模板CStringT的别名
typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;
根据工程设置是Unicode还是多字节,存放的字符串TCHAR不同
这里假定大家都了解Unicode编程
而CStringT的基类是CSimpleStringT
template< typename BaseType, class StringTraits >
class CStringT :
public CSimpleStringT< BaseType, _CSTRING_IMPL_::_MFCDLLTraitsCheck<BaseType, StringTraits>::c_bIsMFCDLLTraits >
而CSimpleStringT重载了操作符
operator PCXSTR() const throw()
{
return( m_pszData );
}
PCXSTR在多字节的环境下,其实就是const char*,在Unicode下是const wchar_t*
一、多字节环境
我们做一下测试,
void CMFCApplication4Dlg::OnBnClickedButton2()
{
CString str("测试");
const char *p = (const char *)str;
}
笔者这里是VS2012
菜单->"调试” -》“窗口”-》反汇编看一下,证明上面的代码确实是调用重载操作符
CString str("测试");
005E8BBD push 1
005E8BBF lea ecx,[str]
005E8BC2 call ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >::__autoclassinit (05C885Ch)
005E8BC7 push 0BC9248h
005E8BCC lea ecx,[str]
005E8BCF call ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > (05C456Dh)
const char *p = (const char *)str;
005E8BD4 lea ecx,[str]
005E8BD7 call ATL::CSimpleStringT<char,0>::operator char const * (05D590Dh)
005E8BDC mov dword ptr [p],eax
}
OK,那么上面的写法,我们可以简单改成
void CMFCApplication4Dlg::OnBnClickedButton2()
{
CString str("测试");
const char *p = str;
}
反汇编看一下,程序默认调用了操作符重载
CString str("测试");
00558BBD push 1
00558BBF lea ecx,[str]
00558BC2 call ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >::__autoclassinit (053885Ch)
00558BC7 push 0B39248h
00558BCC lea ecx,[str]
00558BCF call ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > >::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > (053456Dh)
const char *p = str;
00558BD4 lea ecx,[str]
00558BD7 call ATL::CSimpleStringT<char,0>::operator char const * (054590Dh)
00558BDC mov dword ptr [p],eax
}
也就是说在多字节的环境下,我们可以简单粗暴地把CString传给那个函数参数是const char*的变量
而下面这种直接把CString转成char *却是不行的,因为没有相关的操作符重载
二、Unicode环境下
void CMFCApplication4Dlg::OnBnClickedButton2()
{
CString str(_T("测试"));
const wchar_t *p = (const wchar_t *)str;
}
反汇编下
CString str(_T("测试"));
01158C8D push 1
01158C8F lea ecx,[str]
01158C92 call ATL::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t> > >::__autoclassinit (0112E244h)
01158C97 push 173B298h
01158C9C lea ecx,[str]
01158C9F call ATL::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t> > >::CStringT<wchar_t,StrTraitMFC<wchar_t,ATL::ChTraitsCRT<wchar_t> > > (0113FFE4h)
const wchar_t *p = (const wchar_t *)str;
01158CA4 lea ecx,[str]
01158CA7 call ATL::CSimpleStringT<wchar_t,0>::operator wchar_t const * (011427DFh)
01158CAC mov dword ptr [p],eax
}
说明在Unicode编程环境下,不能简单粗暴地把CString传给那个函数参数是const char*的变量
三、适配2种不同字符环境的写法
void CMFCApplication4Dlg::OnBnClickedButton2()
{
CString str(_T("测试"));
LPCTSTR p = (LPCTSTR)str;
}
好吧,笔者也写了很多年的MFC程序,今天终于花点时间把CString的面纱解开,
大家有看懂的,帮忙点赞一下,谢谢!