【转载】C/C++中的char,wchar,TCHAR

摘要:
TCHAR在使用多字节编码时被定义成char,在Unicode编码时定义成wchar_t。wchar_t*是这样定义的:typedefunsignedshortwchar_t;另外,在头文件中有这样的定义:typedefwchar_tWCHAR;所以WCHAR实际就是wchar_twchar_t*是16-bitUNICODEcharacter(宽字符)所使用的基本类型。

点击这里查看原文章

总体简介:
由于字符编码的不同,在C++中有三种对于字符类型:char, wchar_t , TCHAR。其实TCHAR不能算作一种类型,他紧紧是一个宏。我们都知道,宏在预编译的时候会被替换成相应的内容。TCHAR 在使用多字节编码时被定义成char,在Unicode编码时定义成wchar_t。

1.VC++中的char,wchar_t,TCHAR
大家一起做一个项目,经常发现有的人爱用strcpy等标准ANSI函数,有的人爱用_tXXXX函数,这个问题曾经搞的很混乱。为了统一,有必要把来龙去脉搞清楚。

为了搞清这些函数,就必须理请几种字符类型的写法。char就不用说了,先说一些wchar_t。wchar_t是Unicode字符的数据类型,它实际定义在<string.h>里:
typedef unsigned short wchar_t;
不能使用类似 strcpy这样的ANSI C字符串函数来处理wchar_t字符串,必须使用wcs前缀的函数,例如wcscpy。为了让编译器识别Unicode字符串,必须以在前面加一个 “L”,例如:
wchar_t *szTest=L"This is a Unicode string.";

下面在看看TCHAR。如果你希望同时为ANSI和Unicode编译的源代码,那就要include TChar.h。TCHAR是定义在其中的一个宏,它视你是否定义了_UNICODE宏而定义成char或者wchar_t。如果你使用了TCHAR,那么就不应该使用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必须使用TChar.h中定义的_tcsXXX函数。另外,为了解决刚才提到带“L”的问题,TChar.h中定义了一个宏:“_TEXT”。

以strcpy函数为例子,总结一下:
.如果你想使用ANSI字符串,那么请使用这一套写法:
char szString[100];
strcpy(szString,"test");
.如果你想使用Unicode字符串,那么请使用这一套:
wchar_t szString[100];
wcscpyszString,L"test");
.如果你想通过定义_UNICODE宏,而编译ANSI或者Unicode字符串代码:
TCHAR szString[100];
_tcscpy(szString,_TEXT("test"));

2.字符串及处理之三: 使用TCHAR系列方案
使用TCHAR系列方案编写程序
TCHAR是一种字符串类型,它让你在以MBCS和UNNICODE来build程序时可以使用同样的代码,不需要使用繁琐的宏定义来包含你的代码。
TCHAR的引入,主要是在Tchar.h文件中,该文件包含这方面的重要的定义信息。
对于包含了对str函数或wcs函数进行显式调用的代码来说,无法非常容易地同时为ANSI和Unicode对这些代码进行编译。本章前面说过,可以创建同时为ANSI和Unicode进行编译的单个源代码文件。若要建立双重功能,必须包含TChar.h文件,而不是包含String.h文件。
TChar.h文件的唯一作用是帮助创建ANSI/Unicode通用源代码文件。它包含你应该用在源代码中的一组宏,而不应该直接调用str函数或者 wcs函数。如果在编译源代码文件时定义了_UNICODE,这些宏就会引用wcs这组函数。如果没有定义_UNICODE,那么这些宏将引用str这组宏。
TCHAR的定义如下:
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
所以用MBCS来build时,TCHAR是char,使用UNICODE时,TCHAR是wchar_t。
还有一个宏来处理定义Unicode字符串常量时所需的L前缀。
#ifdef UNICODE
#define _T(x) L##x
#define _TEXT(x) L##x
#define __T(x) L##x
#else
#define _T(x) x
#define _TEXT(x) x
#define __T(x) x
#endif
## 是一个预处理操作符,它可以把两个参数连在一起。如果你的代码中需要字符串常量,在它前面加上_T宏。如果你使用Unicode来build,它会在字符串常量前加上L前缀。
TCHAR szNewText[] = _T("we love Bob!");
_UNICODE宏用于C运行期头文件,而UNICODE宏则用于Windows头文件。当编译源代码模块时,通常必须同时定义这两个宏。
像是用宏来隐藏SetWindowTextA/W的细节一样,还有很多可以供你使用的宏来实现str***()和_mbs***()等字符串函数。例如,你可以使用_tcsrchr宏来替换strrchr()、_mbsrchr()和wcsrchr()。_tcsrchr根据你预定义的宏是_MBCS还是 UNICODE来扩展成正确的函数,就象SetWindowText所作的一样。
不仅str***()函数有TCHAR宏。其他的函数如, _stprintf(代替sprinft()和swprintf()),_tfopen(代替fopen()和_wfopen())。 MSDN中"Generic-Text Routine Mappings."标题下有完整的宏列表。

3.字符串及处理之二: 基本字符串类型及函数
常用的字符串类型有:char * ,wchar_t * ,WCHAR * , TCHAR *
char *
最基本的类型,其对应的一组处理函数是以str...开头的标准的ANSI C字符串函数。
wchar_t *
是这样定义的:typedef unsigned short wchar_t;
另外,在头文件中有这样的定义:typedef wchar_t WCHAR; 所以WCHAR实际就是wchar_t
wchar_t * 是16-bit UNICODE character(宽字符)所使用的基本类型。
其对应的一组处理函数是以wcs...开头的标准的字符串函数。
常用的字符串处理函数和宏:
1、str 开头的 函数 处理SBCS字符串
2、wcs 开头的 函数 处理宽字符串,wcs是宽字符串的英文缩写
所有的unicode函数均以wcs开头。若要调用Unicode函数,只需用前缀wcs来取代ANSI字符串函数的前缀str即可。
对于每一个标准的ANSI C字符串函数,基本都有等价的unicode函数.
3、_mbs 开头的 函数 处理DBCS字符串
微软还在它的CRT(C runtime library)中增加了操作DBCS字符串的版本。Str***()函数都有对应名字的DBCS版本_mbs***()。
如果你料到可能会遇到DBCS字符串(如果你的软件会被安装在使用DBCS编码的国家,如中国,日本等,你就可能会),你应该使用_mbs***()函数,因为他们也可以处理SBCS字符串。(一个DBCS字符串也可能含有单字节字符,这就是为什么_mbs***()函数也能处理SBCS字符串的原因)。微软还提供了几个函数方便对dbcs的处理 , 见后面的描述。
如果只是调用strlen函数,那么你无法真正了解字符串中究竟有多少字符,它只能告诉你到达结尾的0之前有多少个字节。ANSI的C运行期库中没有配备相应的函数,使你能够对双字节字符集进行操作。但是,Microsoft Visual C++的运行期库却包含许多函数,如_mbslen ,它可以用来操作多字节(既包括单字节也包括双字节)字符串。
4、_tcs 开头的 宏 配合TCHAR使用
根据预定义分别扩展为str wcs _mbs, 见后面的描述。
5、l开头的windows自带的宽字符处理函数
6、大小写兼有的 windows自带的宽字符处理函数

5和6见后面的描述
更进一步的字符串以及其指针的类型定义

由于Win32 API文档的函数列表使用函数的常用名字(例如, "SetWindowText"),所有的字符串都是用TCHAR来定义的。(除了XP中引入的只适用于Unicode的API)。下面列出一些常用的 typedefs,你可以在msdn中看到他们。
type Meaning in MBCS builds Meaning in Unicode builds
WCHAR wchar_twchar_t
LPSTR char* char*
LPCSTR const char*const char*
LPWSTR wchar_t*wchar_t*
LPCWSTR const wchar_t* const wchar_t*
TCHAR charwchar_t
LPTSTR TCHAR* TCHAR*
LPCTSTR const TCHAR* const TCHAR*

4.strings(字符串)详解(一)
之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用 = 进行赋值操作,== 进行比较,+ 做串联(是不是很简单?)。我们尽可以把它看成是C++的基本数据类型。
好了,进入正题………
首先,为了在我们的程序中使用 string类型,我们必须包含头文件 <string>。如下:
#include <string> //注意这里不是string.h string.h是C字符串头文件
1.声明一个C++字符串
声明一个字符串变量很简单:
string Str;
这样我们就声明了一个字符串变量,但既然是一个类,就有构造函数和析构函数。上面的声明没有传入参数,所以就直接使用了string的默认的构造函数,这个函数所作的就是把Str初始化为一个空字符串。String类的构造函数和析构函数如下:
a)string s;//生成一个空字符串s
b)string s(str) //拷贝构造函数 生成str的复制品
c)string s(str,stridx) //将字符串str内“始于位置stridx”的部分当作字符串的初值
d)string s(str,stridx,strlen) //将字符串str内“始于stridx且长度顶多strlen”的部分作为字符串的初值
e)string s(cstr) //将C字符串作为s的初值
f)string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。
g)string s(num,c) //生成一个字符串,包含num个c字符
h)string s(beg,end) //以区间beg;end(不包含end)内的字符作为字符串s的初值
i)s.~string() //销毁所有字符,释放内存
都很简单,我就不解释了。
2.字符串操作函数
这里是C++字符串的重点,我先把各种操作函数罗列出来,不喜欢把所有函数都看完的人可以在这里找自己喜欢的函数,再到后面看他的详细解释。
a) =,assign() //赋以新值
b) swap() //交换两个字符串的内容
c) +=,append(),push_back() //在尾部添加字符
d) insert() //插入字符
e) erase() //删除字符
f) clear() //删除全部字符
g) replace() //替换字符
h) + //串联字符串
i) ==,!=,<,<=,>,>=,compare()//比较字符串
j) size(),length()//返回字符数量
k) max_size() //返回字符的可能最大个数
l) empty()//判断字符串是否为空
m) capacity() //返回重新分配之前的字符容量
n) reserve() //保留一定量内存以容纳一定数量的字符
o) [ ], at() //存取单一字符
p) >>,getline() //从stream读取某值
q) <<//将谋值写入stream
r) copy() //将某值赋值为一个C_string
s) c_str() //将内容以C_string返回
t) data() //将内容以字符数组形式返回
u) substr() //返回某个子字符串
v)查找函数
w)begin() end() //提供类似STL的迭代器支持
x) rbegin() rend() //逆向迭代器
y) get_allocator() //返回配置器
下面详细介绍:
2.1 C++字符串和C字符串的转换
C++提供的由C++字符串得到对应的 C_string的方法是使用data()、c_str()和copy(),其中,data()以字符数组的形式返回字符串内容,但并不添加’

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Xcode弱网测试工具使用@supports完美兼容CSS属性下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

G代码简单解释

公司的切割机用的是梅塞尔的等离子切割机,技术部在下发套料图的时候,会将指令文件做简化处理,形式如下: %N4G92X0Y0N6F5000N8G71N10G91N12G00X561.243Y1277.726N14M11N16M09N18G01X75.071Y160.966N20G01X-44.119Y75.746N22G01X86.386Y14.882N24...

免费的天气Web Service接口

免费的天气Web Service接口 在android应用当中很多时候需要获取天气的信息,这里提供怎么获取天气信息: 1. http://www.ayandy.com/Service.asmx?wsdl 官网:http://www.ayandy.com 2. http://webservice.webxml.com.cn/WebServices/Weat...

AVR单片机教程——走向高层

本文隶属于AVR单片机教程系列。   在系列教程的最后一篇中,我将向你推荐3个可以深造的方向:C++、事件驱动、RTOS。掌握这些技术可以帮助你更快、更好地开发更大的项目。 本文涉及到许多概念性的内容,如果你有不同意见,欢迎讨论。 关于高层 这一篇教程叫作“走向高层”。什么是高层? 我认为,如果寥寥几行代码就能实现一个复杂功能,或者一行代码可以对应到几百句...

JsonPath

JsonPath 在xml的使用过程中,对于xml的解析我们知道可以使用xpath的方式,随意的获取到我们想要的属性值。那么在使用json时,我们能不能实现同样的操作呢? 答案就是 json-path 基础介绍 跟 XPath 类似,JsonPath 通过路径来检索JSON,对语法格式如下 语法 符号 描述 $ 表示json的根节点,表示根节点下...

Java中Map用法详解

原文地址http://blog.csdn.net/guomutian911/article/details/45771621 原文地址http://blog.csdn.net/sunny243788557/article/details/52806724 Map以按键/数值对的形式存储数据,这里要特别说明(Map.Entry,是Map的内部类,它用来描述M...

EasyPoi 导入导出Excel时使用GroupName的踩坑解决过程

一、开发功能介绍: 简单的一个excel导入功能 二、Excel导入模板(大致模板没写全): 姓名 性别 生日 客户分类 联系人姓名 联系人部门  备注 材料 综合 采购 张三 男 1994/05/25 1 1 1 张三 开发部   李四 男 1994/05/25 1 1 1 张三 开发部   王五 男 1994/05/25 1 1 1...