Win编程笔记:字符串小结
Basics
ANSI和Unicode:
前者是单字节字符编码,用来表示英语以及一些西欧语言的所有字符;后者是双字节字符编码,可以表示现代计算机涉及的所有字符(包括中文、日文等)。
显然,使用Unicode更有利于国际化和本地化。除此之外,Windows所有核心函数也都需要Unicode字符串。在调用这些函数时,如果传入ANSI字符串,那么这些函数会将其转换成Unicode再执行;反之,如果函数返回ANSI字符串,那么操作系统也是先将其从Unicode字符串转换为ANSI字符串再返回。这样的话,会增加开销,而且埋下一些目前已知的转换函数中存在的bug。
使用Unicode:
ANSI字符是由char类型来表示的,而在win编程中,Unicode字符由wchar_t(wide chartype)来表示的。在使用wchar_t类型时,需要在字符/字符串前加上大写字母L来告诉编译器这是Unicode字符/字符串,如下:
wchar_tc = L'a';
wchar_tstr[10] = L"hello";
为了更有Windows特色,微软做了如下类型定义(WinNT.h):
typedefchar CHAR;
typedefshort SHORT;
typedeflong LONG;
……
typedefwchar_t WCHAR;
在前面加P、LP或者C分别表示指针类型和Const限定,如:
typedef__nullterminated WCHAR*NWPSTR, *LPWSTR,*PWSTR;
……
typedef__nullterminated CONSTWCHAR *LPCWSTR,*PCWSTR;
……
typedef__nullterminated CHAR*NPSTR, *LPSTR,*PSTR;
……
typedef__nullterminated CONSTCHAR *LPCSTR,*PCSTR;
此外,为了更通用一点,微软还做了如下定义:
#ifdef UNICODE //r_winnt
#ifndef_TCHAR_DEFINED
typedefWCHAR TCHAR, *PTCHAR;
……
#define__TEXT(quote)L##quote // r_winnt
#else /* UNICODE */ //r_winnt
#ifndef _TCHAR_DEFINED
typedef char TCHAR, *PTCHAR;
……
#define __TEXT(quote) quote // r_winnt
#endif/* UNICODE */ //r_winnt
#defineTEXT(quote)__TEXT(quote) // r_winnt
即,使用TCHAR(以及PTSTR),无论字符集是ANSI还是Unicode都可以通过编译,与之相应的通用字符串函数也出现了,比如_tcslen(tchar.h):
#ifdef_UNICODE
#define_tcslen wcslen
#else
#define_tcslen strlen
#endif
除了_tcslen,还有一堆其他的字符串处理函数,并且与_tcslen(计算字符串长度)不同,其它很多函数需要考虑安全性,比如_tcscpy或者_tcscat:
#ifdef_UNICODE
#define_tcscat wcscat
#define_tcscat_s wcscat_s
#define_tcscpy wcscpy
#define_tcscpy_s wcscpy_s
#else
#define_tcscat strcat
#define_tcscat_s strcat_s
#define_tcscpy strcpy
#define_tcscpy_s strcpy_s
#endif
紧接着处理函数的都是一个安全版本,这些安全性函数都是添加一个_s后缀,它们检验参数的有效性以及缓冲区是否足以容纳结果。
最后,WinNT.h中还定义了宏TEXT、__TEXT,tchar.h中定义了宏_T、__T、_TEXT,这些宏的功能都是将字符/字符串转换为相应的通用类型,比如:
LPTSTRstr1 = _T("hello,world");
LPTSTRstr2 = TEXT("hello");
ATL字符串
COM字符类型
OLECHAR:不同操作系统上,OLECHAR对应不同字符类型,比如win32上对应wchar_t。
BSTR:一种带长度前缀、含许多特殊语义的OLECHAR字符数组。
ATL字符串转换类
所有类名称都采用“C<源格式缩写>2<目标格式缩写>”的形式,第一个C表示类。缩写中A代表指向char的字符指针(LPSTR)、W代表指向wchar_t的字符指针(LPWSTR)、T代表指向TCHAR的字符指针(LPTSTR)、OLE代表指向OLECHAR的字符指针(LPOLESTR)、C表示const限定符。
以下是字符串转换类:
CA2W CA2WEX CA2T CA2TEX CA2CT CA2CTEX
COLE2T COLE2TEX COLE2CT COLE2CTEX CT2A
CT2AEX CT2CA CT2CAEX CT2OLE CT2OLEEX CT2COLE
CT2COLEEX CT2W CT2WEX CT2CW CT2CWEX CW2A
CW2AEX CW2T CW2TEX CW2CT CW2CTEX
BSTR与CComBSTR
BSTR是指向复合数据类型的指针,该复合数据类型由长度前缀、数据字符串和结束符组成,并且要使用COM内存管理函数来管理BSTR,其专用语义繁多,用法繁琐。
CComBSTR是BSTR的一个封装类。
CComBSTR
CComBSTR类维护一个BSTR类型的public成员m_str。
使用小结如下:
//CComBSTR使用小结
//1.构造
//CComBSTR() {m_str = NULL; }
CComBSTRstr1;
//CComBSTR(LPCOLESTRpSrc);
CComBSTRstr2(LPCOLESTR("hello,world"));
//CComBSTR(intnSize, LPCOLESTR sz);
CComBSTRstr3(5, (LPCOLESTR)NULL);
//CComBSTR(intnSize);
CComBSTRstr4(5);
//CComBSTR(LPCSTRpSrc);
CComBSTRstr5("hello,world");
//CComBSTR(intnSize, LPCSTR sz);
CComBSTRstr6(5,"hello,world");
//CComBSTR(REFGUIDsrc);
static constGUID id_sample =
{ 0x3d8b3644, 0xf90e, 0x4058, { 0x95,0xaf, 0xda, 0x5a, 0xe8, 0x81, 0x8, 0x98 } };
CComBSTRstr7(id_sample);
//2.复制构造函数
//CComBSTR(constCComBSTR& src);
CComBSTRstr8(str2);
//3.析构
//~CComBSTR(){::SysFreeString(m_str); }
//4.赋值
//CComBSTR&operator=(const CComBSTR& src){ ... m_str = src.Copy(); ...}
str3 = str2;
//CComBSTR&operator=(LPCOLESTR pSrc){ ... m_str = ::SysAllocString(pSrc); ... }
str8 = LPCOLESTR("hello,world");
//CComBSTR&operator=(LPCSTR pSrc){ ... m_str = A2WBSTR(pSrc); ... }
str1 = "hello,world";
//HRESULTAssignBSTR(const BSTR bstrSrc){ ... }
BSTR bstrTemp = ::SysAllocString(LPCOLESTR("hello,world"));
CComBSTRstr9;
str9.AssignBSTR(bstrTemp);
//boolLoadString(HINSTANCE hInst, UINT nID);
//从指定模块hInst加载指定的字符串资源nID
//boolLoadString(UINT nID);
//使用全局变量_AtlBaseModule从当前模块加载指定的字符串资源nID
//5.字符串连接
//HRESULTAppend(LPCOLESTR lpsz, int nLen);
//HRESULTAppend(LPCOLESTR lpsz);
//HRESULTAppend(LPCSTR);
//HRESULTAppend(char ch);
//HRESULTAppend(wchar_t ch);
//HRESULTAppend(const CComBSTR& bstrSrc);
//HRESULTAppendBSTR(BSTR p);
//HRESULTAppendBytes(const char * lpsz, int nLen);
//CComBSTR&operator+=(const CComBSTR& bstrSrc);
//6.字符串比较
//bool operator!() const { return (m_str == NULL); }
//operator<()一共有四个重载版本,后面个都是调用第一个,第一个使用VarBstrCmp进行比较
//booloperator<(const CComBSTR& bstrSrc) const{ ... }
//booloperator<(LPCSTR pszSrc) const{ ... }
//booloperator<(LPCOLESTR pszSrc) const{ ... }
//booloperator<(LPOLESTR pszSrc) const{ ... }
//operator>()与operator<()类似
//operator!=()和operator==()则多重载了一个与NULL比较的版本
//7.其它操作
//返回长度
//unsigned intLength() const { return ::SysStringLen(m_str); }
unsigned intlen = str2.Length();
//复制操作
//BSTR Copy() {... }
//HRESULTCopyTo(BSTR* pbstr);
//转换操作
str2.ToLower();
str2.ToUpper();
//HRESULTBSTRToArray(LPSAFEARRAY * ppArray){ ... }
//HRESULTArrayToBSTR(const SAFEARRAY * pSrc){ ... }
//清空操作
str1.Empty();
//附加和分离BSTR
//BSTR Detach() {BSTR s = m_str; m_str = NULL; return s; }
//voidAttach(BSTR src){
// if(m_str != src){
// ::SysFreeString(m_str);
// m_str = src;
// }
//}
CString
从简,使用CString,本质是使用CStringT模板类。
typedefCStringT< wchar_t,StrTraitATL<wchar_t,ChTraitsCRT<wchar_t> > > CAtlStringW;
typedefCStringT< char,StrTraitATL<char,ChTraitsCRT<char> > > CAtlStringA;
typedefCStringT< TCHAR,StrTraitATL<TCHAR,ChTraitsCRT<TCHAR> > > CAtlString;
……
typedefCAtlStringW CStringW;
typedefCAtlStringA CStringA;
typedefCAtlString CString;
……
template<typenameBaseType,classStringTraits>
class CStringT :
public CSimpleStringT……
CStringT继承CSimpleStringT,该基类提供了很多基本字符串功能;BaseType模板参数用来确定字符类型,数据保存在基类私有成员m_pszData中;StringTraits参数确定资源字符串加载的模块、字符串管理器以及提供低级的字符操作。ATL提供了默认的字符串管理器,该管理器是一个实现了IAtlStringMgr的具体类CAtlStringMgr。
CStringT采用了类型定义来处理一些语法分支,XCHAR、PXSTR、PCXSTR代表与模板参数一致的字符类型,而YCHAR、PYSTR、PCYSTR相反。比如如果BaseType为char,则XCHAR代表char,YCHAR代表wchar_t,相应的PXSTR为LPSTR,PYSTR为LPWSTR。
基本使用小结如下:
//CStringT基本使用小结
//1.构造函数
//CStringT();
//explicitCStringT( IAtlStringMgr* pStringMgr );
//CStringT( constCStringT& strSrc );
//CStringT( constCThisSimpleString& strSrc );
//CStringT( constXCHAR* pszSrc );
//CStringT( constXCHAR* pch, int nLength );
//CStringT( constXCHAR* pch, int nLength, IAtlStringMgr* pStringMgr );
//CStringT( PXSTRpszSrc, IAtlStringMgr* pStringMgr );
//以上例,与之相反的YCHAR和PYSTR也可
CStringAcaStr1(L"hello,world");
CStringWcwStr1("hello,world");
CString cStr1;
CString cStr2(cStr1);
CString cStr3("hello,world");
CString cStr4('a', 5);
//2.赋值
//CStringT&operator=( const CStringT& strSrc );
//CStringT&operator=( const CThisSimpleString& strSrc );
//CStringT&operator=( PCXSTR pszSrc );
//CStringT&operator=( XCHAR ch );
//以上两例,YCHAR和PCYSTR也可
caStr1 =L'b';
cwStr1 ='a';
cStr1 = "hello,world";
cStr1 = L"hello,world";
//3.字符串连接
//CStringT&operator+=( const CThisSimpleString& str );
//CStringT&operator+=( const PCXSTR pszSrc );
//CStringT&operator+=( const XCHAR ch );
//以上两例,PCYSTR和YCHAR也可
caStr1+= L'a';
cwStr1+= L"new";
cStr1 +=cStr2;
//+运算
cStr1 + cStr2;
cStr1 + L'a';
cwStr1 +'a';
//Append
//void Append(PCXSTR pszSrc );
//void Append(PCXSTR pszSrc, int nLength );
//void Append(const CSimpleStringT& strSrc );
//voidAppendChar( XCHAR ch );
//4.转换
cStr1.MakeLower();
cStr1.MakeUpper();
cStr1.MakeReverse();
//5.比较
//== != < >
caStr1== L"hello,world";
cwStr1!= "hello,world";
cStr1< cStr2;
//6.其它操作
//增
//int Insert( intiIndex, PCXSTR psz )
//int Insert( intiIndex, XCHAR ch )
cStr1.Insert(0,'a');
//删
//从iIndex开始删除nCount个字符
//int Delete( intiIndex, int nCount = 1 )
//删除所有chRemove字符
//int Remove(XCHAR chRemove )
//改
//int Replace(XCHAR chOld, XCHAR chNew )
//int Replace(PCXSTR pszOld, PCXSTR pszNew )
//查
//int Find( XCHARch, int iStart = 0 ) const
//int Find( PCXSTRpszSub, int iStart = 0 ) const
//int FindOneOf(PCXSTR pszCharSet ) const
//intReverseFind( XCHAR ch ) const
//CStringT Left(int nCount ) const
//CStringT Mid(int iFirst ) const
//CStringT Mid(int iFirst, int nCount ) const
//CStringT Right(int nCount ) const
//XCHARoperator[]( int iChar ) const
str1[3];
//Trim方法
//CStringT&Trim()
//CStringT&Trim( XCHAR chTarget )
//CStringT&Trim( PCXSTR pszTargets )
//CStringT&TrimLeft()
//CStringT&TrimLeft( XCHAR chTarget )
//CStringT&TrimLeft( PCXSTR pszTargets )
//CStringT&TrimRight()
//CStringT&TrimRight( XCHAR chTarget )
//CStringT&TrimRight( PCXSTR pszTargets )
//按指定字符分割
//CStringTTokenize( PCXSTR pszTokens, int & iStart ) const
//CStringT格式化
//void __cdeclFormat( PCXSTR pszFormat, ... );
//void __cdeclFormat( UINT nFormatID, .. )