C++: std::string 与 Unicode 如何结合?
关键字: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 如何结合?的更多相关文章
- C++: std::string 与 Unicode 结合
一旦知道 TCHAR 和_T 是如何工作的,那么这个问题很简单.基本思想是 TCHAR 要么是char,要么是 wchar_t,这取决于_UNICODE 的值: // abridged from tc ...
- 计算std:string的字节长度
如果项目本身是使用 Unicode 字符集和utf8编码,std::string的length(),size()甚至是c的strLen取到的都是字节长度了,比如三个汉字,就是9, 以上情况不满足的话, ...
- CString 与 std::string 相互转化
MFC中CString 与 std::string 相互转化 CString实际是CStringT, 也就是模板类, 在UNICODE环境下,实际是CStringW, 在多字符集环境下,实际是CStr ...
- 关于std::string
主要注意的一个问题是:std::string 实际是类似一个 vector<char>的结构. 它里面是可以存放 ascii为0 的字符不算结尾 (否则 unicode方式的编码存放就有问 ...
- UTF8与std:string互转
Ajax请求发送的UTF8编码字符串传到后台使用std:string进一步处理,如果包含中文会出现中文乱码的问题: 特找了一下转码的解决方法,直接代码如下: C++ Code 1234567891 ...
- C++不存在从std::string转换为LPCWSTR的适当函数
LPCWSTR是什么类型呢? 看看如何定义的: typedef const wchar_t* LPCWSTR; 顾名思义就是: LPCWSTR是一个指向unicode编码字符串的32位指针,所指向字符 ...
- CString和string在unicode与非unicode下的相互转换(转)
原文转自 http://blog.csdn.net/u014303844/article/details/51397556 CString和string在unicode与非unicode下的相互转换 ...
- 对std::string和std::wstring区别的解释,807个赞同,有例子
807down vote string? wstring? std::string is a basic_string templated on a char, and std::wstring on ...
- CString转换成std::string
unicode的编码格式: CString strCS; std::string strSTD = CT2A(strCS.GetBuffer()); 其他的编码格式: CString strCS; ...
随机推荐
- JDBC之数据库操作
JDBC重要界面有: java.sgl.DriverManager:完成驱动程序的装载和建立新的数据库连接. java.sgl.Connection:表示对某一指定数据库的连接. java.sgl.S ...
- 使用subst创建虚拟磁盘及设置分区卷标
最近项目中要研究在"计算机"中添加虚拟磁盘,能够访问某远端目录,同时还要在资源管理器中可以看到创建的虚拟磁盘.关于虚拟磁盘,有几种方式: (1)映射网络磁盘:通过映射网络驱动器,可 ...
- vs2012如何创建报表
引自百度文库,介绍的比较详细 http://wenku.baidu.com/view/c405d5f48762caaedc33d405.html
- Oracle 一些操作
Achivelog ============================ alter system set db_recovery_file_dest='F:\ORACLE\recovery_ar ...
- docker & nodejs
Docker 部署 Node js demo程序 1.准备node js程序,使用express框架. mkdir demo 在demo文件夹下建立package.json { "name& ...
- 动态linq表达式新方法,Dynamic LINQ Extension Method
Remember those old posts on Dynamic LINQ? You are probably aware that Microsoft has made its impleme ...
- .NET Web后台动态加载Css、JS 文件,换肤方案
后台动态加载文件代码: //假设css文件:TestCss.css #region 动态加载css文件 public void AddCss() { HtmlGenericControl _CssFi ...
- ASP.NET文件上传的三种基本方法
ASP.NET依托.net framework类库,封装了大量的功能,使得上传文件非常简单,主要有以下三种基本方法. 方法一:用Web控件FileUpload,上传到网站根目录. <form i ...
- fill与memset的区别
fill 的头文件是<iostream> 命名空间是std: 在memset(a,0(-1),sizeof(a))全部初值定为0或-1时两者是没有多大区别; 但是在初值为其他值得时候就不同 ...
- apache、php隐藏头信息的方法
本文介绍下,在apache与php中隐藏头部信息的方法,有需要的朋友参考下. 一.apache隐藏头部信息 apache 的 httpd.conf 有两个配置可以控制是否显示服务器信息给用户.Serv ...