《转》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。

.使用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();

相关文章
|
13天前
|
编解码 JavaScript 前端开发
【专栏】介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例
【4月更文挑战第29天】本文介绍了字符串Base64编解码的基本原理和在Java、Python、C++、JavaScript及Go等编程语言中的实现示例。Base64编码将24位二进制数据转换为32位可打印字符,用“=”作填充。文中展示了各语言的编码解码代码,帮助开发者理解并应用于实际项目。
|
13天前
|
编译器 C++
【C++进阶】引用 & 函数提高
【C++进阶】引用 & 函数提高
|
17天前
|
存储 编译器 C语言
C++字符串大小写之for语句
C++字符串大小写之for语句
17 0
|
18天前
|
存储 C++
【C++进阶(九)】C++多态深度剖析
【C++进阶(九)】C++多态深度剖析
|
18天前
|
编译器 C++
【C++进阶(八)】C++继承深度剖析
【C++进阶(八)】C++继承深度剖析
|
18天前
|
编译器 C语言 C++
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
【C++进阶(七)】仿函数深度剖析&模板进阶讲解
|
18天前
|
设计模式 C语言 C++
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
【C++进阶(六)】STL大法--栈和队列深度剖析&优先级队列&适配器原理
|
18天前
|
存储 缓存 编译器
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比
【C++进阶(五)】STL大法--list模拟实现以及list和vector的对比
|
18天前
|
算法 C++ 容器
【C++进阶(四)】STL大法--list深度剖析&list迭代器问题探讨
【C++进阶(四)】STL大法--list深度剖析&list迭代器问题探讨
|
18天前
|
编译器 C++
【C++进阶(三)】STL大法--vector迭代器失效&深浅拷贝问题剖析
【C++进阶(三)】STL大法--vector迭代器失效&深浅拷贝问题剖析