热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Unicode介绍及Unicode编程

目录1.什么是Unicode?2.为什么使用Unicode?3.Unicode有什么缺点4.Unicode编程4.1C运行时库对Unicode的

目录

1.什么是Unicode?

2.为什么使用Unicode?

3.Unicode有什么缺点

4.Unicode编程

4.1 C运行时库对Unicode的支持

4.1.1 字符串类型

 4.1.2 字符串处理函数

4.2 用UNICODE宏来编程和控制编译

4.3 编程原则




1.什么是Unicode?

Unicode的学名是"Universal Multiple-Octet Coded Character Set",简称为UCS,也叫统一码、万国码、单一码。


Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

虽然我们经常说unicode编码,但它其实不是一种常规意义上的编码,我认为叫作“编号”更准确,unicode给每个字符都定义了一个不会重复的编号,例如:

“汉”对应的编号是0x6C49

因为每个字符都有不会重复的编号,所有unicode可以表示世界上所有的字符,那么有的人会问汉字有7万多个,而unicode只有2个字节,那它是怎么表示得下呢?

早期的Unicode标准有UCS-2、UCS-4的说法。UCS-2用两个字节编码,UCS-4用4个字节编码。UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个平面(plane)。每个平面根据第3个字节分为256行 (row),每行有256个码位(cell)。group 0的平面0被称作BMP(Basic Multilingual Plane)。将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。每个平面有2^16=65536个码位。unicode规划了17个平面,也就是说一共有17*65536=1114112个码位,可以表示1114112个字符。综上所述,早期的unicode可能确实只有2个字节,但是从UCS-4开始,已经可以支持4个字节了,所以所有的汉字都是能表示得下的。

不要直接把unicode和2个字节划等号,这是不科学的。

那么unicode既然不是一种编码,那编码是什么,我认为编码是一种和计算机通话的规则。例如上面的“汉”字的unicode编号是0x6C49,假设现在有1种编码叫MyUtf,MyUtf会按照它自己的规则把0x6C49的二进制进行一些变换,假设变换成了0x55AA,然后只要告诉计算机当前有个字符用MyUtf来编码的,编码后的值是0x55AA,那么计算机就自动会按照MyUtf的规则进行逆运算,得到0x6C49,并正确的显示一个“汉”字。同样地不管是UTF-8,UTF-16,UTF-32,只要是对UNICODE字符进行编码,那实际上就是对这个编号进行编码,由于编号是固定的,所以不管编码规则如何编号,只要计算机最后能知道你这个编号对应的是UNICODE编号的哪一个就行了,根据编号计算机就能正确的显示出对应的字符,这正是UNICODE标准的意义。

下面是一个用UTF-8对一个UNICODE字符进行编码的示例:

 

 

“汉”字的Unicode编码是0x6C49,将0x6C49写成二进制是: 0110 1100 0100 1001

采用UTF-8的编码规则编码后为:1110 0110 1011 0001 0100 1001,即0xE6B189

那么我们能说UTF-8是UNICODE吗?

当然不能了。

UTF-8 是使用互联网上使用最广泛的 unicode 编码方式,目前已经占有整个互联网 92% 的份额。这里再强调下 UTF-8 只是 Unicode 的一种实现方式,UTF-8 是编码方式,而 Unicode 是字符集合。UTF-8它是可变长的编码方式,长度从 1 个字节到 4 个字节不等。它能够完全兼容 ASCII 码,我们知道 ASCII 码 是由 128 个字符组成的,而 Unicode 中的前 128 个字符和 ASCII 码都是对应的。

我们经常用Visual Studio编程,那么它使用的默认编码是什么呢?

 答案就是-GB2312


2.为什么使用Unicode?

(1)为了不同语言之间进行数据交换

(2)提高应用程序的运行效率


3.Unicode有什么缺点

(1)Unicode字符串占用的内存是ASCII字符串的两倍

(2)相比ASCII字符串而言比较难以理解,很多数程序员都不熟悉或者是似懂非懂,增加了编程的难度


4.Unicode编程

4.1 C运行时库对Unicode的支持


4.1.1 字符串类型

为了使用Unicode字符串,C运行时库中在string.h中定义了一些数据类型,其中wchar_t用来表示一个Unicode字符串,此类型定义如下:

typedef unsigned short wchar_t;

 例如,如果想要创建一个缓存,用于存放最多为9个字符的Unicode字符串和一个结尾为
零的字符,可以使用下面这个语句:

wchar_t buffer[10];

 4.1.2 字符串处理函数

以前我们学习C语言时,经常用到strcpy()、strchr()、strcat()等函数,但是这些函数只能处理单字节的字符串,不能正确处理Unicode字符串。为此,ANSI C提供了一组扩展函数,例如:

char *strcat(char*,const char*);
wchar_t *wcscat(wchar_t*,const wchar_t*);int *strcmp(const char*,const char*);
int *wcscmp(const wchar_t*,const wchar_t*);char *strcpy(char*,const char*);
wchar_t *wcscpy(wchar_t*,const wchar_t*);

注意:

unicode函数均以wcs开头,wcs是宽字符串的英文缩写。若要调用unicode函数,只需用前缀wcs来取代ANSI字符串函数的前缀str即可。


4.2 用UNICODE宏来编程和控制编译

对于调用了以str开头的单字节字符串处理函数的代码,或者是调用了以wcs开头的字符串函数的代码,如果我们想做到可以随便选择编译ANSI版本的程序,还是UNICODE版本的程序,这将很麻烦。

为什么呢?原因如下,比如一旦指定要编译ANSI版本的程序,那么程序中的字符串实际都是单字节的了,但是调用了wcs字符串函数的代码却依然把单字节字符串当成多字节的字符串处理,这肯定会引发异常。一旦指定要编译unicode版本的程序,那么程序中的字符串实际都是双字节的了,但是调用了str字符串函数的代码却依然把双字节字符串当成单字节的字符串处理,这也会引发异常。那么有没有一种方法,可以满足只需要做很小的改动,就可让程序编译成ANSI或UNICODE版本,并且能够正常运行呢?

想要实现上面的目标,只需要包含tchar.h即可,而不是包含string.h。tchar.h通过_UNICODE宏来定义不同版本的字符串类型或者字符串函数。当定义_UNICODE宏时,tchar.h会自动定义UNICODE版本的字符串类型和函数,反之则会自动生成ANSI版本的字符串类型和函数。其内部实现如下:

#ifdef _UNICODE
#define _tcslen wcslen
#else
#define _tcslen strlen#ifdef _UNICODE
#define _T(x) L##x
#else
#define _T(x) x#ifdef _UNICODE
typedef wchar_t TCHAR
#else
typedef char TCHAR

通过上面的说明,我们肯定会想既然这两种写法都有问题,那么正确的打开方式是怎样的呢?
那就是用_TEXT宏或者_T宏来定义字符串,这两个宏的定义如下:

#define _T(x)       __T(x)
#define _TEXT(x)    __T(x)#ifdef _UNICODE
#define __T(x)      L ## x
#else
#define __T(x)      x

使用_T宏,可以将上面的代码改为:

TCHAR buff[100] = _T("hello");


这样改后,不管有没有定义_UNICODE,代码都能编译通过。下面再看一下用_T宏来比较字符

if(buff[0] == _T('H'))
{}

4.3 编程原则

为了避免字符集的兼容性问题,下面是应该遵循的一些基本原则:

  • 将字符串视为字符数组,而不是char数组或字节数组。
  • 将通用数据类型(如TCHAR和PTSTR)用于文本字符和字符串(通用数据类型可以通过定义宏来选择ANSI或者UNICODE版本)。
  • 将显式数据类型(如BYTE和PBYTE)用于字节、字节指针和数据缓存。
  • 将_TTEXT宏或者_T用于字符串前。
  • 执行全局性替换(例如用PTSTR替换PSTR)。
  • 修改字符串运算问题

"修改字符串运算问题"的补充说明

计算字符个数时,使用sizeof(buffer)/sizeof(TCHAR),而不是sizeof(buffer)
计算字节数时,使用charNum*sizeof(TCHAR),而不是charNum(字符个数)




推荐阅读
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • C语言注释工具及快捷键,删除C语言注释工具的实现思路
    本文介绍了C语言中注释的两种方式以及注释的作用,提供了删除C语言注释的工具实现思路,并分享了C语言中注释的快捷键操作方法。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
author-avatar
叹号妈咪_790
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有