说一说ASCLL和Unicode
关于字符编码这个展开来说有太多东西了,这里主要是想说一说最常说的ASCLL和Unicode字符编码的问题,这样至少你在用相关函数的时候,可以搞明白参数的真正含义。
ASCLL编码
计算机就是0和1的世界,所有的东西都是0和1演变而来,对字符来说,也是如此,每个字符在计算机内存中便是就是数字转换成的二进制0、1组合,这个数字就称为该字符的编码。
最常见的就是ACSLL编码了,整个码表对应如下:
| ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 | ASCII值 | 控制字符 |
|---|---|---|---|---|---|---|---|
| 0 | NUT | 32 | (space) | 64 | @ | 96 | 、 |
| 1 | SOH | 33 | ! | 65 | A | 97 | a |
| 2 | STX | 34 | " | 66 | B | 98 | b |
| 3 | ETX | 35 | # | 67 | C | 99 | c |
| 4 | EOT | 36 | $ | 68 | D | 100 | d |
| 5 | ENQ | 37 | % | 69 | E | 101 | e |
| 6 | ACK | 38 | & | 70 | F | 102 | f |
| 7 | BEL | 39 | , | 71 | G | 103 | g |
| 8 | BS | 40 | ( | 72 | H | 104 | h |
| 9 | HT | 41 | ) | 73 | I | 105 | i |
| 10 | LF | 42 | * | 74 | J | 106 | j |
| 11 | VT | 43 | + | 75 | K | 107 | k |
| 12 | FF | 44 | , | 76 | L | 108 | l |
| 13 | CR | 45 | - | 77 | M | 109 | m |
| 14 | SO | 46 | . | 78 | N | 110 | n |
| 15 | SI | 47 | / | 79 | O | 111 | o |
| 16 | DLE | 48 | 0 | 80 | P | 112 | p |
| 17 | DCI | 49 | 1 | 81 | Q | 113 | q |
| 18 | DC2 | 50 | 2 | 82 | R | 114 | r |
| 19 | DC3 | 51 | 3 | 83 | S | 115 | s |
| 20 | DC4 | 52 | 4 | 84 | T | 116 | t |
| 21 | NAK | 53 | 5 | 85 | U | 117 | u |
| 22 | SYN | 54 | 6 | 86 | V | 118 | v |
| 23 | TB | 55 | 7 | 87 | W | 119 | w |
| 24 | CAN | 56 | 8 | 88 | X | 120 | x |
| 25 | EM | 57 | 9 | 89 | Y | 121 | y |
| 26 | SUB | 58 | : | 90 | Z | 122 | z |
| 27 | ESC | 59 | ; | 91 | [ | 123 | { |
| 28 | FS | 60 | < | 92 | / | 124 | | |
| 29 | GS | 61 | = | 93 | ] | 125 | } |
| 30 | RS | 62 | > | 94 | ^ | 126 | ` |
| 31 | US | 63 | ? | 95 | _ | 127 | DEL |
可以看到0-127对应的英文中0-9,a-z,A-Z及控制字符(如换行字符\n等),这些是最基本的英文表达,有了他们我们基本上可以组合出所有的英文表达了。
扩展ASCLL编码
但是这是远远不够的,一些其他欧美国家语言(如德文、法文)有多音字符,还有尽管在最开始ASCLL编码出现的时候还是命令行,但是人们还是想在这上面加些其他的玩意儿,这就有了如下的扩展ACSLL码表了:
可以看到128-255都是一些德文、法文多音字符(上面带点的字符...)和一些希腊符号及其他的符号。
但是注意ACSLL只有0-127字符是标准定义的,扩展ACSLL(128-255)编码表示的字符都是OEM厂商自己定义的,最常用的是IBM的。
再扩展ASCLL
但是这样的扩展在遇到中东文字尤其是东亚如中国的文字后又不行了,那么多汉字,如何用最开始的char(8 bit)编码来表示呢?
如下程序:
- #include <stdio.h>
- int main()
- {
- char a1[] = "a";
- char b1[] = "b";
- char c1[] = "c";
- char a2[] = "我";
- char b2[] = "你";
- char c2[] = "他";
- printf("a1:%d——b1:%d——c1:%d\n", a1[0],b1[0],c1[0]);
- printf("a2:%x——b2:%x——c2:%x\n", a2[0],b2[0],c2[0]);
- printf("a2:%x——b2:%x——c2:%x\n", a2[1],b2[1],c2[1]);
- return 0;
- }
查看内存:
命令行输出结果为:
- a1:97——b1:98——c1:99
- a2:ffffffce——b2:ffffffc4——c2:ffffffcb
- a2:ffffffd2——b2:ffffffe3——c2:fffffffb
哈哈,看到了吧,英文a、b、c在内存是一个字节,但是中文你、我、他在内存中就是两个字节了。
我们可以直接使用printf打印字符,但是一次只能打印一个字节,中文要如上一样分两次打印。
那么中文是如何编码的呢,我们知道传统的ASCLL一个字节最多也只能表示2^8=256个字符,这对于中文是远远不够的,那么就如上所说,中文编码在传统的ASCLL扩展编码的基础上将在第一个字节值是128-255时,在每个字节后附加一个字节,这样就可以表示的字符数为128*256=32768个,一般称为ANSI编码,这对于一般中文表达来说是够了的。
如上的我、你、他编码分别如下(注意低位在前):
我:0xd2ce
你:0xe3c4
他:0xfbcb
代码页
但是这对于一般的表达是够的,问题是中文还有繁体字,还有东亚其他国家的文字如韩国、日本以及中亚等象形字国家的文字,这么多文字也不是32768个编码能够全部表达的。怎么办呢?
针对不同国家不同地区,把常用字符组合成一个ASCLL扩展表并将它们编号,每一个编号表示的扩展表称为一个代码页,现在常见的代码页都有自己的名称,如936代码页就是我们常用的GBK编码,如
950 繁体中文
949 朝鲜语
936 简体中文
932 日语
都是各个国家和地区的代码页。
注意相同的编号在不同的代码页下表示的是不同的字符,
如0xd2ce在中文代码页936对应中文字符我,但是在日语代码页下就不是了。如果代码页设置不正确,很可能显示为乱码,下面我就会演示这一情况。
Unicode编码
上面我们看到了,不同的代码页整的太麻烦了,能不能有一种统一的编码方式来完成编码和字符对应呢?
Unicode就是干这个的。
不同于上面说的同一ANSI编码在不同的代码页下表示不同的字符,同一Unicode编码在任何时候都表示唯一的字符,这你就要问了这得多少个字节才能表示世界上所有的字符啊,哈哈,最简单的就是UTF32编码了,4个字节表示一个字符,总共2^32=4294967296,这下总算够用了。
但是问题是,对于网络传送等场合这样同一个字符要占4个字节,带宽内存什么的浪费了,人们就想到了各式各样的压缩算法:常用的UTF16一般使用两个字节表示常用字符,对于不能表示的或不常用的字符才使用32位编码,这是Windows程序默认的Unicode编码方式;UTF8编码更过分,按照不同的国家文字的多少分别使用1个字节、2个字节、3个字节和4个字节表示,常用于网络传速。
对于如下程序:
- #include <Windows.h>
- #include <stdio.h>
- #include <locale.h>
- int main()
- {
- wchar_t a1[] = L"a";
- wchar_t b1[] = L"b";
- wchar_t c1[] = L"c";
- wchar_t a2[] = L"我";
- wchar_t b2[] = L"你";
- wchar_t c2[] = L"他";
- wprintf_s(L"a1:%x——b1:%x——c1:%x\n", a1[0], b1[0], c1[0]);
- wprintf_s(L"我:%x——你:%x——他:%x\n", a2[0], b2[0], c2[0]);
- _locale_t lt = _get_current_locale();
- printf_s("\n之前代码页:%s\n", (lt->locinfo)->lc_category[0].locale);
- _wsetlocale(LC_ALL, L"chs");
- lt = _get_current_locale();
- wprintf_s(L"现在代码页:%s\n", (lt->locinfo)->lc_category[0].wlocale);
- wprintf_s(L"\na1:%x——b1:%x——c1:%x\n", a1[0], b1[0], c1[0]);
- wprintf_s(L"我:%x——你:%x——他:%x\n", a2[0], b2[0], c2[0]);
- return 0;
- }
查看内存:
程序运行结果为:
- a1:61
- 之前代码页:(null)
- 现在代码页:Chinese (Simplified)_People's Republic of China.936
- a1:61——b1:62——c1:63
- 我:6211——你:4f60——他:4ed6
现在看到了乱码现象吧?第一次输出a1,b1,c1,a2,b2,c2时只能输出一部分,转换不正确出不来。
这是因为控制台程序显示只能使用ANSI方式,可以右键查看属性,如下:
即显示默认的是使用简体中文代码页936,即GBK编码。
我们在内存中的字符编码是Unicode方式,要显示到GBK编码的控制台窗口上,必须经过编码转换,那么编码转换依据什么呢,就是依靠当前的代码页来完成转换的。
如对于字符"我"的转换过程:
Unicode编码:0x6211->对应字符:"我"->查询代码页936->ANSI编码:0xd2ce
反之亦然。
最开始没有正确设置转换用的代码页,所以转换不正确,也就不能正确显示,设置转换用的代码页后就可以正常显示了。
在windows中的编码转换函数MultiByteToWideChar和WideCharToMultiByte的第一个参数都是codepage,即设定用于编码转换的表(代码页)。
现在你应该明白为什么很多时候和场合要设置locale了吧,设置不同的locale就是对应不同的代码页,这样显示转换才能成功,对应的常见场合有网页显示和数据库数据读取。
那关于编码的问题就这么多了,弄懂整个编码演变历史和过程,我们使用相关函数的时候就没有什么大问题了。
演示源代码下载链接
原创,转载请注明来自http://blog.csdn.net/wenzhou1219
说一说ASCLL和Unicode的更多相关文章
- ASCLL、Unicode和UTF-8编码的理解
我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题. 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit) ...
- Python学习:基本概念
Python学习:基本概念 一,python的特点: 1,python应用场景多;爬虫,网站,数据挖掘,可视化演示. 2,python运行速度慢,但如果CPU够强,这差距并不明显. 3,严格的缩进式编 ...
- python注释方法以及编码问题
一.单行注释 在python中常使用"#"来进行单行注释,其快捷键为"ctrl+/",如果要对多行代码也就是代码块进行注释时,也可以选中多行按下 "c ...
- HTML基础学习笔记(2)
HTML学习笔记(2) 1 head标签中的结构 编码结构:<meta charset="UTF-8"> charset---编码 ascll ansi Unicode ...
- html基础标签下
1.1 单标签 ◆注释标签 ctrl+/ ◆水平线标签 <hr> ◆换行标签 <br> 1.2 双标签 ◆段落标签 <p></p> ◆ ...
- 2017年5月24日 HTML 基础知识(二)
1 快捷方式:html:xt +tab 过渡XHTML html:xs+tab 严格XHTML !+tab html5的标签结构 2.Charset 编码 <meta charset ...
- 老齐python-基础2(字符串)
1.字符串 1.1索引和切片 索引: >>> lang = "study python" >>> lang[0] 's' >>> ...
- Microsoft SQL Server Transact-SQL
Microsoft SQL Server Transact-SQL 1.SQL 1.1数据定义语言(DDL) create 创建数据库或数据库对象:alter 修改数据库或数据库对象:drop 删除数 ...
- python中文编码 - python基础入门(5)
python到目前为止,一共有两个版本,分别是2.x和3.x版本,根据官方正式通知2020年停止对python更新和维护,距离今天还有110天左右,所以正在学习python的小伙伴应该暗中庆幸一波. ...
随机推荐
- WPF 自定义CheckBox
WPF中原始的CheckBox样式很简单,有时候不适用于WPF那种炫酷的界面. 本章节讲述如何设计一个匹配业务需要.好看的CheckBox(继上篇<WPF-自定义ListBox>中的Che ...
- 实验楼 linux 学习
实验楼 linux 学习 一.Linux 用户管理 1.查看用户 who am i // who mom likes whoami ====--------====== 输入的第一列表示打 ...
- postman使用之四:切换环境和设置读取变量
postman提供了environment管理功能,想要在多个环境中测试,比如在测试环境.灰度环境.生产环境等,只需要用同样的接口,切换下环境即可,非常方便.具体步骤: 切换环境 1.点击界面右上角的 ...
- Linux下管道编程
功能: 父进程创建一个子进程父进程负责读用户终端输入,并写入管道 子进程从管道接收字符流写入另一个文件 代码: #include <stdio.h> #include <unistd ...
- 洛谷P1220关路灯[区间DP]
题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯. 为了给村 ...
- POJ3928Ping pong[树状数组 仿逆序对]
Ping pong Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3109 Accepted: 1148 Descrip ...
- 嵌入式Linux驱动学习之路(二十三)NAND FLASH驱动程序
NAND FLASH是一个存储芯片. 在芯片上的DATA0-DATA7上既能传输数据也能传输地址. 当ALE为高电平时传输的是地址. 当CLE为高电平时传输的是命令. 当ALE和CLE都为低电平时传输 ...
- 上海闪酷成为京东商城第一批独立软件开发商(ISV)
闪酷信息技术(上海)有限公司一直致力于为品牌企业提供电子商务软件及其服务,为其拓展电商渠道保驾护航.上海闪酷依据多年的行业经验和技术积累,与中国 最大的B2C商城达成战略合作,为其2万多家品牌供应商提 ...
- Qt——设计颜色编辑器
Qt中有一些封装好的对话框,比如QMessageBox.QColorDialog等,用途很广,但缺点是样式难以改变,直接拿来用可能与我们自己的系统样式不搭配,显得很难看. 所以我在无聊的时候,就自己写 ...
- C#进阶系列——MEF实现设计上的“松耦合”(二)
前言:前篇 C#进阶系列——MEF实现设计上的“松耦合”(一) 介绍了下MEF的基础用法,让我们对MEF有了一个抽象的认识.当然MEF的用法可能不限于此,比如MEF的目录服务.目录筛选.重组部件等高级 ...