一、wchar 和 wstring 的定义:
1、数据类型为 wchar(宽字符)的变量长度为 16 位,占用2个 byte 的内存。 wchar 数据类型将扩展字符集中的单个字符保存为 UFT-16 编码形式。
2、数据类型为 wstring (宽字符串)的操作数用于在一个字符串中存储多个数据类型为 wchar 的 Unicode 字符。如果未指定长度,则字符串的长度为预置的 254 个字。
Unicode 是国际标准字符集,可译为万国码或统一码等,包含中日韩越汉字和世界上绝大多数语言文字。
二、wchar 和 wstring 在西门子 PLC 中的格式
本节以汉字为例说明汉字在西门子 PLC 中的格式。
例如,在 PLC 中创建一个 DB 块,并将属性设置为标准 DB 块,在 DB1 块中创建如下的汉字字符串和汉字字符,并赋予起始值。如下图所示:
1、wstring 数据类型的格式
下载到 PLC 中,通过监视表逐个查看每个字中的值。如下图所示:
可以看出:
a.数据类型为 wstring 的汉字字符串,通过查看 DB 块偏移地址可见该字符串占用254字;查看字符串第一个字,其最多存储汉字字符总数量为254个。
b.数据类型为 wstring[10] 的汉字字符串,通过查看 DB 块偏移地址可见该字符串占用12字;查看字符串第一个字,其最多存储汉字字符数量为10个。
c.汉字字符串的第一个字为该字符串总长度,第二个字为当前存储的有效字符数量。
2、wchar 和16进制数的关系
在计算机领域,所有的数据都是以2进制数存储的,那么 wchar,16进制数和2进制数又有什么关系?
如下图所示:
可以看出:
a.通过汉字字符 '好' 的16进制数和2进制数,可见字符(wchar)、16进制数只是在PLC中显示的形式不同,实际存储的是一个2进制值。
通过下面的网页,可以查看汉字和16进制数的对应关系。
b.通过汉字字符 '1' 的16进制数和2进制数,可见汉字字符(wchar)'1' 显示的16进制数为16#0031,而字符(char)'1' 对应的16进制数为16#31。因此,如果使用 wchar 存储仅占一个字节的 char 字符时,则高八位为16#00,低八位是相同的,都是2进制的2#0011_0001。
三、常问问题:
1、定义为 wstring 的字符串,是否能保存数字和英文字母的字符?
可以。
例如,wchar#'A',实际存储时,对应的16进制数为16#0041,wchar#'1',实际存储时,对应的16进制数为16#0031。
如下图所示:
也就是说,使用 wchar 存储仅占一个字节的英文字母或数字时,对应 wchar 的字的高八位将为16#00。
2、如何输入特殊字符(如:回车,换行,$ 等)?
例如,需要输入的汉字字符串为 '$早上好$+回车+换行',可以参考如下表格:
根据表格说明,字符串在 PLC 中的书写格式:'$$早上好$$$R$L'或'$$早上好$$$N',如下图所示:
三、Unicode 码:
统一码(Unicode),也叫万国码、单一码,由统一码联盟开发,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。
统一码是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
发展历程
编辑 播报
1990年开始研发,1994年正式发布1.0版本,2022年9月13日发布15.0版本。 [2]
统一码统一码简介
编辑 播报
如果把各种文字编码形容为各地的方言,那么统一码就是世界各国合作开发的一种语言。
在这种语言环境下,不会再有语言的编码冲突,在同屏下,可以显示任何语言的内容,这就是统一码的最大好处。就是将世界上所有的文字用2个字节统一进行编码。那样,像这样统一编码,2个字节就已经足够容纳世界上所有语言的大部分文字了。
Universal Multiple-Octet Coded Character Set,简称为UCS。
现在用的是UCS-2,即2个字节编码,而UCS-4是为了防止将来2个字节不够用才开发的。
统一码是一种在计算机上使用的字符编码,1990年开始研发,1994年正式公布。随着计算机工作能力的增强,统一码也在面世以来的十多年里得到普及。
统一码是基于通用字符集(Universal Character Set)的标准来发展,同时也以出版物的形式(The 统一码 Standard,目前第五版由Addison-Wesley Professional出版,ISBN-10: 0321480910)对外发表。
2005年3月31日推出4.1.0版本。
2022年9月13日推出15.0版本。 [2]
统一码编码和实现
编辑 播报
大概来说,统一码编码系统可分为编码方式和实现方式两个层次。
统一码编码方式
统一码是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。统一码用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。
统一码字符集可以简写为UCS(统一码Character Set)。早期的统一码标准有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个码位。统一码计划使用了17个平面,一共有17*65536=1114112个码位。在统一码 5.0.0版本中,已定义的码位只有238605个,分布在平面0、平面1、平面2、平面14、平面15、平面16。其中平面15和平面16上只是定义了两个各占65534个码位的专用区(Private Use Area),分别是0xF0000-0xFFFFD和0x100000-0x10FFFD。所谓专用区,就是保留给大家放自定义字符的区域,可以简写为PUA。
平面0也有一个专用区:0xE000-0xF8FF,有6400个码位。平面0的0xD800-0xDFFF,共2048个码位,是一个被称作代理区(Surrogate)的特殊区域。代理区的目的用两个UTF-16字符表示BMP以外的字符。在介绍UTF-16编码时会介绍。
如前所述在统一码5.0.0版本中,238605-65534*2-6400-2408=99089。余下的99089个已定义码位分布在平面0、平面1、平面2和平面14上,它们对应着统一码定义的99089个字符,其中包括71226个汉字。平面0、平面1、平面2和平面14上分别定义了52080、3419、43253和337个字符。平面2的43253个字符都是汉字。平面0上定义了27973个汉字。
统一码实现方式
在统一码中,汉字“字”对应的数字是23383。在统一码中,我们有很多方式将数字23383表示成程序中的数据,包括:UTF-8、UTF-16、UTF-32。UTF是“UCS Transformation Format”的缩写,可以翻译成统一码字符集转换格式,即怎样将统一码定义的数字转换成程序数据。例如,“汉字”对应的数字是0x6c49和0x5b57,而编码的程序数据是:
BYTE data_utf8[] = {0xE6, 0xB1, 0x89, 0xE5, 0xAD, 0x97}; // UTF-8编码
WORD data_utf16[] = {0x6c49, 0x5b57}; // UTF-16编码
DWORD data_utf32[] = {0x6c49, 0x5b57}; // UTF-32编码
这里用BYTE、WORD、DWORD分别表示无符号8位整数,无符号16位整数和无符号32位整数。UTF-8、UTF-16、UTF-32分别以BYTE、WORD、DWORD作为编码单位。“汉字”的UTF-8编码需要6个字节。“汉字”的UTF-16编码需要两个WORD,大小是4个字节。“汉字”的UTF-32编码需要两个DWORD,大小是8个字节。根据字节序的不同,UTF-16可以被实现为UTF-16LE或UTF-16BE,UTF-32可以被实现为UTF-32LE或UTF-32BE。下面介绍UTF-8、UTF-16、UTF-32、字节序和BOM。
UTF-8
UTF-8以字节为单位对统一码进行编码。从统一码到UTF-8的编码方式如下:
统一码编码(十六进制)║UTF-8字节流(二进制)
F║0xxxxxxxx║110xxxxx 10xxxxxx║1110xxxx 10xxxxxx 10xxx10xxxx║11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。统一码的最大码位0x10FFFF也只有21位。
例1:“汉”字的统一码编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001,用这个比特流依次代替模板中的x,得到:1110 0110 1011 0001 1000 1001,即E6 B1 89。
例2:统一码编码0x20C30在0x010000-0x10FFFF之间,使用用4字节模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。将0x20C30写成21位二进制数字(不足21位就在前面补0):0 0010 0000 1100 0011 0000,用这个比特流依次代替模板中的x,得到:,即F0 A0 B0 B0。
UTF-16
UTF-16编码以16位无符号整数为单位。我们把统一码编码记作U。编码规则如下:
如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整数记作WORD)。
如果U≥0x10000,我们先计算U'=U-0x10000,然后将U'写成二进制形式:yyyy yyyy yyxx xxxx xxxx,U的UTF-16编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。
为什么U'可以被写成20个二进制位?统一码的最大码位是0x10ffff,减去0x10000后,U'的最大值是0xfffff,所以肯定可以用20个二进制位表示。例如:统一码编码0x20C30,减去0x10000后,得到0x10C30,写成二进制是:0001 0000 1100 0011 0000。用前10位依次替代模板中的y,用后10位依次替代模板中的x,就得到:1101 1000 0100 0011 和 1101 1100 0011 0000,即0xD843 0xDC30。
按照上述规则,统一码编码0x10000-0x10FFFF的UTF-16编码有两个WORD,第一个WORD的高6位是110110,第二个WORD的高6位是110111。可见,第一个WORD的取值范围(二进制)是到1111111111,即0xD800-0xDBFF。第二个WORD的取值范围(二进制)是到11011111 11111111,即0xDC00-0xDFFF。
为了将一个WORD的UTF-16编码与两个WORD的UTF-16编码区分开来,统一码编码的设计者将0xD800-0xDFFF保留下来,并称为代理区(Surrogate):
D800-DB7F ║ High Surrogates ║ 高位替代
DB80-DBFF ║ High Private Use Surrogates ║ 高位专用替代
DC00-DFFF ║ Low Surrogates ║ 低位替代
高位替代就是指这个范围的码位是两个WORD的UTF-16编码的第一个WORD。低位替代就是指这个范围的码位是两个WORD的UTF-16编码的第二个WORD。那么,高位专用替代是什么意思?我们来解答这个问题,顺便看看怎么由UTF-16编码推导统一码编码。
如果一个字符的UTF-16编码的第一个WORD在0xDB80到0xDBFF之间,那么它的统一码编码在什么范围内?我们知道第二个WORD的取值范围是0xDC00-0xDFFF,所以这个字符的UTF-16编码范围应该是0xDB80 0xDC00到0xDBFF 0xDFFF。我们将这个范围写成二进制:
110100 - 11
按照编码的相反步骤,取出高低WORD的后10位,并拼在一起,得到
0 1111 1111 1111 1111
即0xe0000-0xfffff,按照编码的相反步骤再加上0x10000,得到0xf0000-0x10ffff。这就是UTF-16编码的第一个WORD在0xdb80到0xdbff之间的统一码编码范围,即平面15和平面16。因为统一码标准将平面15和平面16都作为专用区,所以0xDB80到0xDBFF之间的保留码位被称作高位专用替代。
UTF-32
UTF-32编码以32位无符号整数为单位。统一码的UTF-32编码就是其对应的32位无符号整数。
根据字节序的不同,UTF-16可以被实现为UTF-16LE或UTF-16BE,UTF-32可以被实现为UTF-32LE或UTF-32BE。例如:
统一码编码║ UTF-16LE ║ UTF-16BE ║ UTF32-LE ║ UTF32-BE
0x006C49 ║ 49 6C ║ 6C 49 ║ 49 6C 00 00 ║ 00 00 6C 49
0x020C30 ║ 43 D8 30 DC ║ D8 43 DC 30 ║ 30 0C 02 00 ║ 00 02 0C 30
判断字节流的字节序
统一码标准建议用BOM(Byte Order Mark)来区分字节序,即在传输字节流前,先传输被作为BOM的字符"零宽无中断空格"。这个字符的编码是FEFF,而反过来的FFFE(UTF-16)和FFFE0000(UTF-32)在统一码中都是未定义的码位,不应出现在实际传输中。下表是各种UTF编码的BOM:
UTF编码 ║ Byte Order Mark
UTF-8 ║ EF BB BF
UTF-16LE ║ FF FE
UTF-16BE ║ FE FF
UTF-32LE ║ FF FE 00 00
UTF-32BE ║ 00 00 FE FF
基本上,计算机只是处理数字。它们指定一个数字,来储存字母或其他字符。在创造统一码之前,有数百种指定这些数字的编码系统。没有一个编码可以包含足够的字符:例如,单单欧洲共同体就需要好几种不同的编码来包括所有的语言。即使是单一种语言,例如英语,也没有哪一个编码可以适用于所有的字母,标点符号,和常用的技术符号。这些编码系统也会互相冲突。也就是说,两种编码可能使用相同的数字代表两个不同的字符,或使用不同的数字代表相同的字符。任何一台特定的计算机(特别是服务器)都需要支持许多不同的编码,但是,不论什么时候数据通过不同的编码或平台之间,那些数据总会有损坏的危险。