Unicode介绍及Unicode编程

Unicode编程详解:原理、优缺点与C运行时库支持
本文详细介绍了Unicode的概念,包括它的作用、发展历程和与ASCII的区别。Unicode是为了支持跨语言文本处理而设计的,允许表示全球多种语言的字符。尽管Unicode占用的内存比ASCII多,但提供了更大的字符覆盖范围。在C编程中,Unicode通过宽字符类型(wchar_t)和特定的字符串处理函数(如wcscat、wcscmp)得到支持。通过定义_UNICODE宏,开发者可以在代码中灵活切换ANSI和UNICODE版本。遵循使用TCHAR和_TEXT宏的编程原则,可以确保代码的兼容性。

目录

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(字符个数)

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Allen Roson

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值