关键字:std::string Unicode

转自:http://www.vckbase.com/document/viewdoc/?id=1293

一旦知道 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 之间的实用差别是微不足道的。

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

  1. C++: std::string 与 Unicode 结合

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

  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. DOS批处理命令-goto命令

    goto是一个流程控制语句 rem goto语句是一个大家都不怎么喜欢的语句,因为他的随意性太强,导致可维护性大大的降低. 语法: goto [lable]   [lable]是bat程序中任意定义的 ...

  2. 第三篇、微信小程序-网络请求API

    wx.request(OBJECT)发起的是https请求.一个微信小程序,同时只能有5个网络请求连接. OBJECT参数说明: 效果图: net.js Page({ data:{ result:{} ...

  3. 第四十二篇、自定义Log打印

    1.在Xcode 8出来之后,需要我们去关闭多余的日志信息打印 2.在开发的过程中,打印调试日志是一项比不可少的工程,但是在iOS 10中NSLog打印日志被屏蔽了,就不得不使用自定义Log 3.去掉 ...

  4. Visual Studio下SQLite数据库开发环境设置

    由于我们介绍的内容都是基于微软的Visual Studio下开发的Win32平台,所以下边我们介绍Visual Studio下SQLite数据库开发环境设置.具体而言我们有两种方式可以在Visual ...

  5. block回调具体例子

    //main.m ////  main.m//  回调////  Created by hehe on 15/9/10.//  Copyright (c) 2015年 wang.hehe. All r ...

  6. 详解null

    前言 在java中初始化的时候经常用到null,也经常会碰到空指针异常(NullPointerException),由于碰到的频率比较高,我认为有必要进行一下了解,揭开它的神秘面纱. 一.null是代 ...

  7. InnoDB 离线转储工具

    一,应用场景; 1,表空间严重损坏,无法恢复;2,数据库表空间文件丢失后从磁盘上打捞出部分数据页面;3,恢复删除记录; 二,功能; 从数据页中直接转储出文本格式的行数据,从而可以后期用 LOAD DA ...

  8. bzoj 1040 骑士

    这题真不爽,各种WA,写个题解浏览器还挂了,真不爽. 所以不多说了,就说关于判断是否是父节点的问题,不能直接判,会有重边,这种情况只能用编号判,传进去入边的编号,(k^1) != fa,这样就可以了. ...

  9. Brackets - 又一款牛x的WEB开发编辑器

    Brackets官网下载: http://brackets.io/ Adobe Brackets是由Adobe主导开发一款主打web开发的编辑器. 是继TextMate,Sublime Text这两个 ...

  10. DTCMS中文章增加tags标签和关键词时中文,替换为英文状态,

    DTCMS.Web\admin\article\article_edit.aspx 找到添加和修改的方法 model.tags = txtTags.Text.Trim()model.seo_keywo ...