一旦知道 TCHAR 和_T 是如何工作的,那么这个问题很简单。基本思想是 TCHAR 要么是char,要么是 wchar_t,这取决于_UNICODE 的值:

// abridged from tchar.h 

#ifdef _UNICODE
typedef wchar_t TCHAR;
#define __T(x) L ## x
#else
typedef char TCHAR;
#define __T(x) x
#endif

  当你在工程设置中选择 Unicode 字符集时,编译器会用 _UNICODE 定义进行编译。如果你选择MBCS(多字节字符集),则编译器将不会带 _UNICODE 定义 。一切取决于_UNICODE 的值。同样,每一个使用字符指针的 Windows API 函数会有一个 A(ASCII) 和一个 (Wide/Unicode) 版本,这些版本的 实际定义也是根据 _UNICODE 的值来决定:

#ifdef UNICODE
#define CreateFile CreateFileW
#else
#define CreateFile CreateFileA
#endif

  同样,_tprintf 和 _tscanf 对应于 printf 和 scanf。所有带"t"的版本使用 TCHARs 取代了chars。那么怎样把以上的这些应用到 std::string 上呢?很简单。STL已经有一个使用宽字符定义的wstring类 (在 xstring 头文件中定义)。string 和 wstring 均是使用 typedef 定义的模板类,基于 basic_string, 用它可以创建任何字符类型的字符串类。以下就是 STL 定义的 string 和 wstring

//(frominclude/xstring)
typedef basic_string< char, char_traits< char >, allocator< char > > string;
typedef basic_string< wchar_t, char_traits< wchar_t >, allocator< wchar_t > > wstring;

  模板被潜在的字符类型(char 或 wchar_t)参数化,因此,对于 TCHAR 版本,所要做的就是使用 TCHAR 来模仿定义:

typedef basic_string< TCHAR, char_traits< TCHAR >, allocator< TCHAR > > tstring; 

  现在便有了一个 tstring,它基于 TCHAR——也就是说,它要么是 char,要么是 wchar_t,这取决于 _UNICODE 的值。 以上示范并指出了STL 是怎样使用 basic_string 来实现基于任何类型的字符串的。定义一个新的 typedef 并不是解决此问题最有效的方法。一个更好的方法是基于 string 和wstring 来简单 地定义 tstring,如下:

ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif

  这个方法之所以更好,是因为 STL 中已经定义了 string 和 wstring,那为什么还要使用模板来定义一个新的和其中之一一样的字符串类呢? 暂且叫它 tstring。可以用 #define 将 tstring 定义为 string 和 wstring,这样可以避免创建另外一个模板类( 虽然当今的编译器非常智能,如果它把该副本类丢弃,我一点也不奇怪)。[typedef 不创建新类,只是为某个类型引入限定范围的名称,typedef 决不会定义一个新的类型]。不管怎样,一旦定义了 tstring,便可以像下面这样编码:

tstring s = _T("Hello, world");
_tprintf(_T("s =%s\n"), s.c_str());

basic_string::c_str 方法返回一个指向潜在字符类型的常量指针;在这里,该字符类型要么是const char*,要么是const wchar_t*。

  顺便说一下,MFC 和 ATL 现在已经联姻,以便都使用相同的字符串实现。结合后的实现使用一个叫做 CStringT 的模板类,这在某种意义上 ,其机制类似 STL 的 basic_string,用它可以根据任何潜在的字符类型来创建 CString 类。在 MFC 包含文件afxstr.h中定义了三种字符 串类型,如下:

typedef ATL::CStringT< wchar_t, StrTraitMFC< wchar_t > > CStringW;
typedef ATL::CStringT< char, StrTraitMFC< char > > CStringA;
typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;

CStringW,CStringA 和 CString 正是你所期望的:CString 的宽字符,ASCII 和 TCHAR 版本。

  那么,哪一个更好,STL 还是 CStirng?两者都很好,你可以选择你最喜欢的一个。但有一个问题要考虑到:就是你想要链接哪个库,以及你是否已经在使用 MFC/ATL。从编码 的角度来看,我更喜欢 CString 的两个特性:

  其一是无论使用宽字符还是char,都可以很方便地对 CString 进行初始化。

CString s1 = "foo";

CString s2 = _T("bar");

  这两个初始化都正常工作,因为 CString 自己进行了所有必要的转换。使用 STL 字符串,你必须使用_T()对tstring 进行初始化,因为你 无法通过一个char*初始化一个wstring,反之亦然。

  其二是 CString 对 LPCTSTR 的自动转换操作,你可以像下面这样编码:

CString s;

LPCTSTR lpsz = s;

  另一方面,使用 STL 必须显式调用 c_str 来完成这种转换。这确实有点挑剔,某些人会争辩说,这样能更好地了解何时进行转换。比如, 在C风格可变参数的函数中使用 CString 可能会有麻烦,像 printf:

printf("s=%s\n", s); // 错误

printf("s=%s\n", (LPCTSTR)s); // 必需的

  没有强制类型转换的话,得到的是一些垃圾结果,因为 printf 希望 s 是 char*。我敢肯定很多读者都犯过这种错误。防止这种灾祸是 STL 设计者不提供转换操作符的一个毋庸置疑的理由。而是坚持要你调用 c_str。一般来讲,喜欢使用 STL 家伙趋向于理论和学究气,而 Redmontonians(译者:指微软)的大佬们则更注重实用和散漫。嘿,不管怎样,std::string 和 CString 之间的实用差别是微不足道的。

C++: std::string 与 Unicode 结合的更多相关文章

  1. C++: std::string 与 Unicode 如何结合?

    关键字:std::string Unicode 转自:http://www.vckbase.com/document/viewdoc/?id=1293 一旦知道 TCHAR 和_T 是如何工作的,那么 ...

  2. 计算std:string的字节长度

    如果项目本身是使用 Unicode 字符集和utf8编码,std::string的length(),size()甚至是c的strLen取到的都是字节长度了,比如三个汉字,就是9, 以上情况不满足的话, ...

  3. CString 与 std::string 相互转化

    MFC中CString 与 std::string 相互转化 CString实际是CStringT, 也就是模板类, 在UNICODE环境下,实际是CStringW, 在多字符集环境下,实际是CStr ...

  4. 关于std::string

    主要注意的一个问题是:std::string 实际是类似一个 vector<char>的结构. 它里面是可以存放 ascii为0 的字符不算结尾 (否则 unicode方式的编码存放就有问 ...

  5. UTF8与std:string互转

    Ajax请求发送的UTF8编码字符串传到后台使用std:string进一步处理,如果包含中文会出现中文乱码的问题: 特找了一下转码的解决方法,直接代码如下:  C++ Code  1234567891 ...

  6. C++不存在从std::string转换为LPCWSTR的适当函数

    LPCWSTR是什么类型呢? 看看如何定义的: typedef const wchar_t* LPCWSTR; 顾名思义就是: LPCWSTR是一个指向unicode编码字符串的32位指针,所指向字符 ...

  7. CString和string在unicode与非unicode下的相互转换(转)

    原文转自 http://blog.csdn.net/u014303844/article/details/51397556 CString和string在unicode与非unicode下的相互转换 ...

  8. 对std::string和std::wstring区别的解释,807个赞同,有例子

    807down vote string? wstring? std::string is a basic_string templated on a char, and std::wstring on ...

  9. CString转换成std::string

    unicode的编码格式: CString strCS; std::string strSTD =  CT2A(strCS.GetBuffer()); 其他的编码格式: CString strCS; ...

随机推荐

  1. FindViewByMe插件

    FindViewByMe 是一个自动生成 FindViewById 代码的 IDEA/Android Studio 插件, 支持 Activity.Fragment 和 ViewHolder 中的 f ...

  2. Android APP高效开发的十大建议

    在使用Android开发APP过程中,为什么确保最优化.运行流畅且不会使Android系统出现问题至关重要呢?因为影响APP产品效率的每一个问题,如:耗电或内存占用情况等,都是关乎APP成功与否关键因 ...

  3. CE_现金模组基本概念(概念)

    2014-07-12 Created By BaoXinjian

  4. 触发隐藏链接进行文件下载,click无响应

    function invokeClick(element) { if (element.click) element.click(); //判断是否支持click() 事件 else if (elem ...

  5. 转-Fragment+FragmentTabHost组件(实现新浪微博底部菜单)

    http://www.cnblogs.com/lichenwei/p/3985121.html 记得之前写过2篇关于底部菜单的实现,由于使用的是过时的TabHost类,虽然一样可以实现我们想要的效果, ...

  6. 词典对象 NSDictionary与NSMutableDictionary

    做过Java语言或者 C语言开发的朋友应该很清楚关键字map 吧,它可以将数据以键值对儿的形式储存起来,取值的时候通过KEY就可以直接拿到对应的值,非常方便,是一种非常常用的数据结构.在Objecti ...

  7. Spring中的AOP应用

    AOP被称为面向切面编程,AOP中的几个重要概念是: 1.切面.切面就是要实现的功能.切面通常是在多数方法中会用到的相同功能,如写日志. 2.连接点.连接点就是应用程序执行过程中插入切面的地点.如:方 ...

  8. ubuntu命令查补

    Linux删除目录的命令有:rm,rm命令删除目录虽说比较简单,不过一旦所操作的目录非空时,就会让你陷入深深的苦恼之中 rm -rf 目录名字: -r 就是向下递归,管理有多少级目录,一并删除 -f ...

  9. 线程间操作无效: 从不是创建控件“”的线程访问它~~~的解决方法~ 线程间操作无效: 从不是创建控件“Control Name'”的线程访问它问题的解决方案及原理分析

    看两个例子,一个是在一个进程里设置另外一个进程中控件的属性.另外一个是在一个进程里获取另外一个进程中控件的属性. 第一个例子 最近,在做一个使用线程控制下载文件的小程序(使用进度条控件显示下载进度)时 ...

  10. [SQL]SQL语言入门级教材_SQL语言快速入门(五)

    SQL语言快速入门(一) SQL是英文Structured Query Language的缩写,意思为结构化查询语言. SQL语言的主要功能就是同各种数据库建立联系,进行沟通.按照ANSI(美国国家标 ...