tstring
是的,一旦知道 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) 和一个 W(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:
// (from include/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,这样可以避免创建另外一个模板类( 虽然当今的编译器非常智能,如果它把该副本类丢弃,我一点也不奇怪)。[编辑更新-2004/07/30: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*。
Figure 2 是一个简单的示范程序,举例说明了 tstring 的用法。它将“Hello,world”写入一个文件,并报告写了多少个字节。我对 工程进行了设置,以便用 Unicode 生成 debug 版本,用 MBCS 生成 Release 版本。你可以分别进行编译/生成并运行程序,然后比较结果。Figure 3 显示了例子的运行情况。
Figure 3 运行中的 tstring
顺便说一下,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 之间的实用差别是微不足道的
tstring的更多相关文章
- delphi TString使用(取有规律的字符串中某一项内容)
{目的,取得下面字符串中的每一项内容,如s:='a,b,c,d',要去的用逗号隔开的每一项内容这时采用Tstring,会方便很多,TString是继承TStringList带有List所有属性.} v ...
- 使用自定义的tstring.h
UNICODE 控制函数是否用宽字符版本_UNICODE 控制字符串是否用宽字符集 _T("") 根据上述定义来解释字符集 // 在tchar.h中 // tstring.h ...
- lua解析赋值类型代码的过程
我们来看看lua vm在解析下面源码并生成bytecode时的整个过程: foo = "bar" local a, b = "a", "b" ...
- Delphi容器类之---TList、TStringList、TObjectList,以及一个例程的代码分析
转载自:http://blog.csdn.net/jqandjq/article/details/5429137 看了这里标题,大家可能以为我会谈TListBox控件,那就错了.我要谈的是Delphi ...
- 转:Delphi 6 实用函数
来自: daocaoren0824, 时间: -- ::, ID: 再给你一份 程序员实用函数 {▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎} {▎ ▎} {▎ 大 ...
- HDU---BigZhuGod的粉丝
Problem Description 真正的粉丝,是不需要题目描述的^_^. Input 第一行输入数据组数T(1≤T≤100).接下来T行,每行一个有格式的字符串,详见样例,字符串长度不超过1 ...
- lua解析脚本过程中的关键数据结构介绍
在这一篇文章中我先来介绍一下lua解析一个脚本文件时要用到的一些关键的数据结构,为将来的一系列代码分析打下一个良好的基础.在整个过程中,比较重要的几个源码文件分别是:llex.h,lparse.h.l ...
- lua中的string类型
在lua中用union TString来表示字符串类型 lobject.h: 其中结构体tsv中 reserved字段表示字符串是不是保留关键字,hash是其哈希值,len是其长度.我们在TStrin ...
- 极简MarkDown排版介绍(How to)
如何切换编辑器 切换博客园编辑器为MarkDown:MarkDown Editor 选择一个在线编辑和预览站点:StackEdit 如何排版章节 MarkDown: 大标题 ========== 小标 ...
随机推荐
- 纯 CSS 创建各种不同的图形形状
使用代码 矩形 .rectangle { width: 250px; height: 150px; background-color: #6DC75F; } <div></div&g ...
- C#方法的使用
static void Main(string[] arr) { , ); Console.WriteLine(max); Console.ReadKey(); } /// <summary&g ...
- 学习OpenSeadragon之四(导航视图)
OpenSeadragon介绍以及上手:学习OpenSeadragon之一 OpenSeadragon主要用于地图.医学图像等需要放大缩小分层显示的图像显示. 1.简单例子 导航视图就是在一个小框中显 ...
- 认识cocos2d-x jsbinding
近年来HTML5风起云涌,特别在移动端已经被更多的人熟识.H5跨平台,在线更新等特性,被人们津津乐道.然后就出现了各种H5的框架,甚至多达100种,真是让开发者眼花缭乱,笔者作为一个从事H5游戏开发一 ...
- Redis+PHP扩展的安装和Redis集群的配置 与 PHP负载均衡开发方案
以前有想过用 Memcache 实现M/S架构的负载均衡方案,直到听说了 Redis 后才发现它做得更好.发了几天时间研究了一下 Redis ,感觉真的很不错,特整理一下! 以下操作都是在 SUSE ...
- 不要依赖hibernate的二级缓存
一.hibernate的二级缓存 如果开启了二级缓存,hibernate在执行任何一次查询的之后,都会把得到的结果集放到缓存中,缓存结构可以看作是一个hash table,key是数据库记录的id ...
- c语言实现BMP图像转换为灰度图
当初是自己要装X,非要用c来写信息隐藏作业,装了X,就得付出实践.查了好久资料,到期末才把作业交了,这里总结一下. 这道题是将真彩图转换为灰度图. 关于BMP文件结构,这是困扰了我好久的问题,上网查了 ...
- python中列表和字典的高级应用
1.将序列分解为单独的变量 1.1问题 包含n个元素的元组或列表.字符串.文件.迭代器.生成器,将它分解为n个变量 1.2方案 直接通过赋值操作 要求:变量个数要等于元素个数 当执行分解操作时,有时需 ...
- Go Cookie 练习
package main import ( "io" "log" "net/http" ) func main() { http.Handl ...
- 转:CRect类 的介绍
类CRect是对Windows结构RECT的封装,凡是能用RECT结构的地方都可以用CRect代替. 结构RECT表示一个矩形的位置和尺寸,其定义为: typedef struct tagRECT{ ...