《转》c++ 字符串系列:字符编码进阶(下)
五.使用TCHAR
TCHAR是一种字符串类型,它让你在以MBCS和UNNICODE来build程序时可以使用同样的代码,不需要使用繁琐的宏定义来包含你的代码。TCHAR的定义如下:
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
所以用MBCS来build时,TCHAR是char,使用UNICODE时,TCHAR是wchar_t。还有一个宏来处理定义Unicode字符串常量时所需的L前缀。
#ifdef UNICODE
#define _T(x) L##x
#else
#define _T(x) x
#endif
##是一个预处理操作符,它可以把两个参数连在一起。如果你的代码中需要字符串常量,在它前面加上_T宏。如果你使用Unicode来build,它会在字符串常量前加上L前缀。像是用宏来隐藏SetWindowTextA/W的细节一样,还有很多可以供你使用的宏来实现str***()和_mbs***()等字符串函数。例如,你可以使用_tcsrchr宏来替换strrchr()、_mbsrchr()和wcsrchr()。_tcsrchr根据你预定义的宏是_MBCS还是UNICODE来扩展成正确的函数,就像SetWindowText所作的一样。
不仅str***()函数有TCHAR宏。其他的函数如, _stprintf(代替sprinft()和swprintf()),_tfopen(代替fopen()和_wfopen())。 MSDN中"Generic-Text Routine Mappings."标题下有完整的宏列表。
六.字符串宏定义
由于Win32 API文档的函数列表使用函数的常用名字(例如,"SetWindowText"),所有的字符串都是用TCHAR来定义的。(除了XP中引入的只适用于Unicode的API)。下面列出一些常用的typedefs,你可以在MSDN中看到他们。
type |
Meaning in MBCS builds |
Meaning in Unicode builds |
LPSTR |
char* | char * |
LPCSTR |
const char* | const char* |
WCHAR |
wchar_t | wchar_t |
LPWSTR |
wchar_t* | wchar_t* |
LPCWSTR |
const wchar_t* | const wchar_t* |
TCHAR |
char | wchar_t |
LPTSTR |
TCHAR* | TCHAR* |
LPCTSTR |
const TCHAR* | const TCHAR* |
一个增加的字符类型是OLETYPE。它表示自动化接口(如word提供的可以使你操作文档的接口)中使用的字符类型。这种类型一般被定义成wchar_t,然而如果你定义了OLE2ANSI预处理标记,OLECHAR将会被定义成char类型。我知道现在已经没有理由定义OLE2ANSI(从MFC3以后,微软已经不使用它了),所以从现在起我将把OLECHAR当作Unicode字符。
这里给出你将会看到的一些OLECHAR相关的typedefs:
type | meaning |
OLECHAR |
Unicode character (wchar_t) |
LPOLESTR |
string of OLECHAR (OLECHAR*) |
LPCOLESTR |
constant string of OLECHAR (const OLECHAR*) |
还有两个用于字符串和字符常量的宏定义,它们可以使同样的代码被用于MBCS和Unicode builds:
type | meaning |
_T |
Prepends L to the literal in Unicode builds. |
OLESTR(x) |
Prepends L to the literal to make it an LPCOLESTR. |
在文档或例程中,你还会看到好多_T的变体。有四个等价的宏定义,它们是TEXT, _TEXT, __TEXT和__T,它们都起同样的做用。
七.字符串扩展类型及封装类
字符串的种类多种多样,有些可以应用在很多场合(比如C字符串的基础char类型),也有一些可能只是在特定情况下才会使用(比如使用MFC一般会用到CString,而开发COM组件一般会涉及到BSTR或CComBSTR)。希望通过下面的总结能让大家清楚地了解到各种不同类型字符串的出处和通常情况下的使用场合。
封闭类 | 出处 | 功能简介 | 使用 |
BSTR | COM | 特殊的字符串类型可以保存字符串长度 | 需要调用专门的API函数,容易造成内存泄漏。建议使用封闭类,比如CComBSTR. |
VARIANT | COM | 特殊结构,被设计用来实现跨语言的特性 | 用来在无类型语言如(Jscript和VBScript)来传递数据 |
CString | MFC | 封闭TCHAR类型字符串 | MFC中使用 |
ColVariant | MFC | 继承自VARIANT | 很少用 |
_bstr_t | CRT | 是一纣BSTR的完整封闭类,隐藏了底层的BSTR | |
_variant_t | CRT | 是一个对VARIANT 的完整封闭,隐藏了底层的VARIANT | |
basic_string | STL | 类模板 | string wstring |
CComBSTR | ATL | BSTR的封闭类,可直接讯问底层BSTR | 在某些情况下比_bstr_t有用的多 |
CComVariant | ATl |
VARIANT的封装类,但是VARIANT没有被隐藏。 |
|
CString |
WTL |
行为和MFC的 CString完全一样。 |
|
System::String |
CLR 和 VC 7 类 |
一个String对象包含一个不可改变的字符串序列。 |
八.常用字符串转换
1、函数 WideCharToMultiByte(),转换 UNICODE 到 MBCS。使用范例:
LPCOLESTR lpw = L"Hello,你好";
size_t wLen = wcslen( lpw ) + 1; // 宽字符字符长度,+1表示包含字符串结束符
int aLen=WideCharToMultiByte( // 第一次调用,计算所需 MBCS 字符串字节长度
CP_ACP,
0,
lpw, // 宽字符串指针
wLen, // 字符长度
NULL,
0, // 参数0表示计算转换后的字符空间
NULL,
NULL);
LPSTR lpa = new char [aLen];
WideCharToMultiByte(
CP_ACP,
0,
lpw,
wLen,
lpa, // 转换后的字符串指针
aLen, // 给出空间大小
NULL,
NULL);
// 此时,lpa 中保存着转换后的 MBCS 字符串
... ... ... ...
delete [] lpa;
2、函数 MultiByteToWideChar(),转换 MBCS 到 UNICODE。使用范例:
LPCSTR lpa = "Hello,你好";
size_t aLen = strlen( lpa ) + 1;
int wLen = MultiByteToWideChar(
CP_ACP,
0,
lpa,
aLen,
NULL,
0);
LPOLESTR lpw = new WCHAR [wLen];
MultiByteToWideChar(
CP_ACP,
0,
lpa,
aLen,
lpw,
wLen);
... ... ... ...
delete [] lpw;
3、使用 ATL 提供的转换宏。
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 的缩写 |
使用范例:
#include <atlconv.h>
void fun()
{
USES_CONVERSION; // 只需要调用一次,就可以在函数中进行多次转换
LPCTSTR lp = OLE2CT( L"Hello,你好") );
... ... ... ...
// 不用显式释放 lp 的内存,因为
// 由于 ATL 转换宏使用栈作为临时空间,函数结束后会自动释放栈空间。
}
使用 ATL 转换宏,由于不用释放临时空间,所以使用起来非常方便。但是考虑到栈空间的尺寸(VC 默认2M),使用时要注意几点:
1、只适合于进行短字符串的转换;
2、不要试图在一个次数比较多的循环体内进行转换;
3、不要试图对字符型文件内容进行转换,因为文件尺寸一般情况下是比较大的;
4、对情况 2 和 3,要使用 MultiByteToWideChar() 和 WideCharToMultiByte();