VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 2393|回复: 30

[原创] C++: std::string 与 Unicode 如何结合?

[复制链接]
79_avatar_middle
在线会员 发表于 2016-1-16 13:15:34 | 显示全部楼层 |阅读模式
C++: std::string 与 Unicode 如何结合?
一旦知道 TCHAR 和_T 是如何工作的,那么这个问题很简单。基本思想是 TCHAR 要么是char,要么是 wchar_t,这取决于_UNICODE 的值:





   1: // abridged from tchar.h    2:     3: #ifdef _UNICODE   4:     5:       typedef wchar_t TCHAR;   6:     7:       #define __T(x) L ## x   8:     9: #else  10:    11:      typedef char TCHAR;  12:    13:      #define __T(x) x  14:    15: #endif  当你在工程设置中选择 Unicode 字符集时,编译器会用 _UNICODE 定义进行编译。如果你选择MBCS(多字节字符集),则编译器将不会带 _UNICODE 定义 。一切取决于_UNICODE 的值。同样,每一个使用字符指针的 Windows API 函数会有一个 A(ASCII) 和一个 (Wide/Unicode) 版本,这些版本的 实际定义也是根据 _UNICODE 的值来决定:



   1:     2:  #ifdef UNICODE   3:     #define CreateFile CreateFileW   4:  #else   5:    #define CreateFile CreateFileA   6:  #endif

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

   1:     2:   //(frominclude/xstring)   3:   typedef basic_string< char, char_traits< char >, allocator< char > > string;   4:   typedef basic_string< wchar_t, char_traits< wchar_t >, allocator< wchar_t > > wstring;

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

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

   1: #ifdef _UNICODE   2:    #define tstring wstring   3: #else   4:    #define tstring string   5: #endif

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

   1: tstring s = _T("Hello, world");   2: _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中定义了三种字符 串类型,如下:

   1: typedef ATL::CStringT< wchar_t, StrTraitMFC< wchar_t > > CStringW;   2: typedef ATL::CStringT< char, StrTraitMFC< char > > CStringA;   3: 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 之间的实用差别是微不足道的。
由于工作比较忙 所以好久都没发帖子了 抽时间总结一下我的经验和看法, 希望大家支持,看过要加分和热心哦

评分

参与人数 4驿站币 +6 热心值 +6 收起 理由
88_avatar_small 寂寞江湖 + 2 + 2 支持原创!
26_avatar_small snsset + 1 + 1 感谢分享!
16_avatar_small 阳光 + 1 + 1 赞一个!
65_avatar_small 编程者 + 2 + 2 写的不少 辛苦了

查看全部评分





上一篇:#ifdef的用法
下一篇:内存分配及清空、调试 几种方法的总结
24_avatar_middle
在线会员 发表于 2016-1-16 14:44:32 | 显示全部楼层
来看看你的心得
65_avatar_middle
donate_vip 发表于 2016-1-16 18:25:08 | 显示全部楼层
看看 怎么 写的
72_avatar_middle
online_vip 发表于 2016-1-17 00:29:07 | 显示全部楼层
看看好不好呢
84_avatar_middle
在线会员 发表于 2016-1-17 11:44:20 | 显示全部楼层
Unicode的问题很头痛
44_avatar_middle
online_vip 发表于 2016-1-17 13:56:54 | 显示全部楼层
我个人写了一个tstring.
#ifdef _UNICODE
   typedef tstring wstring
#else
   typedef tstring string
#endif
02_avatar_middle
在线会员 发表于 2016-1-18 08:19:56 | 显示全部楼层
看看是如何结合
25_avatar_middle
在线会员 发表于 2016-1-18 09:02:02 | 显示全部楼层
C++: std::string 与 Unicode 如何结合?C++: std::string 与 Unicode 如何结合?
17_avatar_middle
在线会员 发表于 2016-1-19 10:18:18 | 显示全部楼层
谢谢分享!C++: std::string 与 Unicode 如何结合?
43_avatar_middle
在线会员 发表于 2016-1-19 10:35:19 | 显示全部楼层
6楼正解,呵呵
17_avatar_middle
online_vip 发表于 2016-1-19 17:57:22 | 显示全部楼层
DDDDDDDDDDDDDDDDDDDDDDDDDD
16_avatar_middle
在线会员 发表于 2016-2-6 13:31:56 | 显示全部楼层
谢谢分享啊
92_avatar_middle
online_vip 发表于 2016-2-6 15:39:07 | 显示全部楼层
怎么都得回复啊
50_avatar_middle
在线会员 发表于 2016-2-6 20:53:35 | 显示全部楼层
谢谢关心谢谢分享
72_avatar_middle
在线会员 发表于 2016-2-8 11:29:36 | 显示全部楼层
看看什么情况
49_avatar_middle
在线会员 发表于 2016-2-8 12:25:56 | 显示全部楼层
看看  !!!
32_avatar_middle
online_vip 发表于 2016-2-8 16:17:37 | 显示全部楼层
来看看你的心得
49_avatar_middle
online_vip 发表于 2016-2-19 14:11:00 | 显示全部楼层
CMenu类之我见
45_avatar_middle
online_vip 发表于 2016-2-25 14:02:30 | 显示全部楼层
支持一下
55_avatar_middle
在线会员 发表于 2016-2-26 15:28:55 | 显示全部楼层
!!!!!!!!!!!!!!!!!!!!!!!!!!!!
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2019-3-21 14:55

Powered by Discuz! X3.4

© 2009-2019 cctry.com

快速回复 返回顶部 返回列表