Unicode字符集的出现是为了弥补ASCII码只能表示128个字符的限制。在实际应用中,如若我们想显示汉字或日文等等,显然使用ASCII是不可能的。Unicode占用了两个字节,即16位,能表示的字符高达65536。即使像汉字这样庞大的语言,也不过3W左右的字符,所以Unicode足够应付。当然实际中可能很少用到这种字符集,咱们可以将其作为一项拓展知识面来了解下。

在C语言中,我们有如下定义:char c='A';变量c只需要一个字节来保存,并用十六进制数0x41来初始化,0x41是A的ASCII码。

我们也可以定义:char *p = “hello!”;因为windows是一个32位的操作系统,所以指针变量p需要四个字节来保存。当然,后面的字符串需要7个字节来保存。

宽字符

Unicode或者宽字符都没有改变char数据型态在C中的含义。char继续表示1个字节的储存空间,sizeof (char)继续返回1。理论上,C中1个字节可比8位长,但对我们大多数人来说,1个字节(也就是1个char)是8位宽。

C中的宽字符基于wchar_t数据型态,它在几个表头文件包括WCHAR.H中都有定义,像这样:

typedef unsigned short wchar_t ;

因此,wchar_t数据型态与无符号短整数型态相同,都是16位宽。

要定义包含一个宽字符的变量,可使用下面的语句:

wchar_t c = 'A' ;

变量c是一个双字节值0x0041,是Unicode表示的字母A。(然而,因为Intel微处理器从最小的字节开始储存多字节数值,该字节实际上是以0x41、0x00的顺序保存在内存中。如果检查Unicode文字的计算机储存应注意这一点。)

您还可定义指向宽字符串的指针:

wchar_t * p = L"Hello!" ;

注意紧接在第一个引号前面的大写字母L(代表「long」)。这将告诉编译器该字符串按宽字符保存-即每个字符占用2个字节。通常,指针变量p要占用4个字节,而字符串变量需要14个字节-每个字符需要2个字节,末尾的0还需要2个字节。

同样,您还可以用下面的语句定义宽字符数组:

static wchar_t a[] = L"Hello!" ;

该字符串也需要14个字节的储存空间,sizeof (a) 将返回14。索引数组a可得到单独的字符。a[1] 的值是宽字符「e」,或者0x0065。

虽然看上去更像一个印刷符号,但第一个引号前面的L非常重要,并且在两个符号之间必须没有空格。只有带有L,编译器才知道您需要将字符串存为每个字符2字节。稍后,当我们看到使用宽字符串而不是变量定义时,您还会遇到第一个引号前面的L。幸运的是,如果忘记了包含L,C编译器通常会给提出警告或错误信息。

您还可在单个字符文字前面使用L前缀,来表示它们应解释为宽字符。如下所示:

wchar_t c = L'A' ;

但通常这是不必要的,C编译器会对该字符进行扩充,使它成为宽字符。

宽字符链接库函数

我们都知道如何获得字符串的长度。例如,如果我们已经像下面这样定义了一个字符串指针:

char * pc = "Hello!" ;

我们可以呼叫

iLength = strlen (pc) ;

这时变量iLength将等于6,也就是字符串中的字符数。

太好了!现在让我们试着定义一个指向宽字符的指针:

wchar_t * pw = L"Hello!" ;

再次呼叫strlen :

iLength = strlen (pw) ;

现在麻烦来了。首先,C编译器会显示一条警告消息,可能是这样的内容:

'function' : incompatible types - from 'unsigned short *' to 'const char *'

这条消息的意思是:声明strlen函数时,该函数应接收char类型的指标,但它现在却接收了一个unsigned short类型的指标。您仍然可编译并执行该程序,但您会发现iLength等于1。为什么?

字符串「Hello!」中的6个字符占用16位:

0x0048 0x0065 0x006C 0x006C 0x006F 0x0021

Intel处理器在内存中将其存为:

48 00 65 00 6C 00 6C 00 6F 00 21 00

假定strlen函数正试图得到一个字符串的长度,并把第1个字节作为字符开始计数,但接着假定如果下一个字节是0,则表示字符串结束。

strlen函数的宽字符版是wcslen(wide-character string length:宽字符串长度),并且在STRING.H(其中也说明了strlen)和WCHAR.H中均有说明。strlen函数说明如下:

size_t __cdecl strlen (const char *) ;

而wcslen函数则说明如下:

size_t __cdecl wcslen (const wchar_t *) ;

对于一段程序而言,但由于执行时期链接库函数有不同的名称(strlen,wcslen),为此需要定义不同的字符,但这将在处理前面带有L的字符串文字时遇到麻烦。

为解决此问题,windows提供一个TCHAR.H的表头文件。该头文件不是标准C的一部分,因此该头文件中所定义的每个函数个宏定义的前面都有一条底线。TCHAR.H为需要字符串参数的标准执行时期链接库的函数提供了一系列的替代名称(如_tcslen或者_tprintf)。有时这些名称也称为“通用”函数名称,因为他们即可以指向函数的Unicode版也可以指向非Unicode版。

针对计算字符串长度而言,TCHAR.H中声明了strlen()和wcslen()的通用函数_tcslen()函数;char和换字符wchar_t的通用变量TCHAR;以及_tcslen()函数中参数字符串以及宽字符串的通用参数_T(x)或_TEXT(x)。

那么程序调用链接库的时候是如何知道通用函数或通用类型等等代表哪个函数或类型呢?

如果定义了名为_UNICODE的标识符,并且程序中包含了TCHAR.H表头文件,那么_tcslen就定义为wcslen:

#define _tcslen wcslen

如果没有定义UNICODE,则_tcslen定义为strlen:

#define _tcslen strlen

等等。TCHAR.H还用一个新的数据型态TCHAR来解决两种字符数据型态的问题。如果定义了_UNICODE标识符,那么TCHAR就是wchar_t:

typedef wchar_t TCHAR ;

否则,TCHAR就是Char:

typedef char TCHAR ;

现在开始讨论字符串文字中的L问题。如果定义了_UNICODE标识符,那么一个称作__T的宏就定义如下:

#define __T(x) L##x

这是相当晦涩的语法,但合乎ANSI C标准的前置处理器规范。那一对井字号称为「粘贴符号(token paste)」,它将字母L添加到宏参数上。因此,如果宏参数是"Hello!",则L##x就是L"Hello!"。

如果没有定义_UNICODE标识符,则__T宏只简单地定义如下:

#define __T(x) x

此外,还有两个宏与__T定义相同:

#define _T(x)__T(x)

#define _TEXT(x)__T(x)

在Win32 console程序中使用哪个宏,取决于您喜欢简洁还是详细。基本地,必须按下述方法在_T或_TEXT宏内定义字符串文字:

_TEXT ("Hello!")

这样做的话,如果定义了_UNICODE,那么该串将解释为宽字符的组合,否则解释为8位的字符字符串。

Unicode字符集的更多相关文章

  1. 【JavaScript】浅析javaScript和HTML与unicode字符集的关系

    目录结构: // contents structure [-] javaScript和HTML的字符集 javaScript和HTML如何表现unicode字符集 参考文章 javaScript和HT ...

  2. Unicode字符集下CString与char *转换 (解决中文乱码等)(转)

    UniCode 下 CString 转 char* 的方法的文章有很多,但是大部分都是在互相转载,看了那么多资料,仍然没有解决乱码的问题,后来从一个论坛的一条回复里面找到了正确的方法,特此拿出来与大家 ...

  3. zzy:java采用的是16位的Unicode字符集作为编码方式------理解

    java语言使用16位的Unicode字符集作为编码方式,是疯狂Java中的原话. 1,编码方式只是针对字符类型的(不包括字符串类,数值类型int等,这些只是在解释[执行]的时候放到Jvm的不同内存块 ...

  4. UNICODE字符集(20140520)

    1多字节字符集,如"IT学吧",sizeof内存长度为7,因为前面2个字母各占用一个字节,后面两个汉字各占用2个字节,结尾的\0占用一个字节.strlen即字符串长度的结果为6. ...

  5. Unicode 字符集及UTF-8 UTF-16编码

    很久以前发在他处的一篇博文,今天翻出来重新整理了一下 Unicode 字符集 共分为 17 个平面(plane), 分别对应 U+xx0000 - U+xxFFFF 的 code points, 其中 ...

  6. Unicode字符集下CString与char *相互转换

    经常遇到CString转换char*时只返回第一个字符.原因是因为在Unicode字符集下CString会以Unicode的形式来保存数据,强制类型转换只会返回第一个字符.所以直接转换在基于MBCS的 ...

  7. 《windows核心编程系列》二谈谈ANSI和Unicode字符集 .

    http://blog.csdn.net/ithzhang/article/details/7916732转载请注明出处!! 第二章:字符和字符串处理 使用vc编程时项目-->属性-->常 ...

  8. 关于Unicode字符集

    最初的unicode编码是固定长度的,16位,也就是2两个字节代表一个字符,这样一共可以表示65536个字符.显然,这样要表示各种语言中所有的字符是远远不够的.Unicode4.0规范考虑到了这种情况 ...

  9. 刨根究底字符编码之十——Unicode字符集的字符编码方式CEF

    Unicode字符集的字符编码方式CEF 一.字符编码方式CEF的选择 1. 由于Unicode字符集非常大,有些字符的编号(码点值)需要两个或两个以上字节来表示,而要对这样的编号进行编码,也必须使用 ...

  10. ASCII字符集。扩展ASCII字符集。Unicode字符集分别支持多少个字符?

    ASCII字符集.扩展ASCII字符集.Unicode字符集分别支持多少个字符? 256个字符和 65536个字符

随机推荐

  1. Leetcode:9. Palindrome Number

    这题要求不能使用额外的空间,我也就没做,看了下别人的代码,挺有意义的一道题目,出坏了. 解题思路:从右往左颠倒过来,看看这个值和原来的x值是不是一样,最后还要注意像20这种情况,也是的 public ...

  2. Java学习之多态(Polymorphism)

    多态==晚绑定 不要把函数重载理解为多态. 因为多态是一种运行期的行为,不是编译期的行为. 多态:父类型的引用可以指向子类型的对象. 比如 Parent p = new Child(); 当使用多态方 ...

  3. 10.Ubuntu16搭建蜜罐Cowrie

    一直都想尝试搭建一个蜜罐,因为蜜罐是一款可以对ssh,telnet,http等等协议攻击进行记录,对于输入命令和上传文件均有记录的一款软件. 记录可以设置在日志文件中或者通过配置数据库,导入数据库中方 ...

  4. .net动态代理-EMIT,AOP实现

    动态代理实现原理: 通过动态基础目标类,重写目标虚方法,.net中实现手段-il Emit.Proxy项目源码,https://github.com/1448376744/Emit.Proxy 以下是 ...

  5. jmeter场景设计实战(一)

    需求:2000用户在线,100用户并发访问首页. 和开发沟通了解了具体的需求:2000用户是在线登录状态,这2000用户中要达到100用户并发去访问首页,在这个过程中可能会有停留时间,并不是用户登录之 ...

  6. File类、递归

    File类.递归 1.1File类概述 java.io.File表示文件和目录路径名的抽象类.可以对文件和文件夹进行创建删除.获取.判断.遍历等功能. 1.2路径\文件分割符,相对路径绝度路径 1.2 ...

  7. php数组处理函数

    array_reverse()数组反向排序,$arr=array_reverse($arr)

  8. sql 存储过程-proc

    创建 create proc 存储过程名 (参数列表) as sql 语句 go 执行 exec 存储过程名 参数1,参数2 删除 drop procedure  存储过程名 注: 存储过程名最好以_ ...

  9. python 3.x 安装问题及连接oracle数据库

    最近有用到python去处理一些问题,发现现在3已出来,遂用直接下3.7使用 发现问题还是有一点的 1. pip 会出现ssl问题 Could not install packages due to ...

  10. gulp的watch记事本

    let gulp=require('gulp'), nodemon=require('gulp-nodemon'), browser=require('browser-sync'); let relo ...