说一说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的小伙伴应该暗中庆幸一波. ...
随机推荐
- Python简单练习
#coding=UTF-8 a=10; b=2; c=a+b; print (c); score=90; if score>=80: print ("很好"); elif s ...
- 关于LogStash运行在AIX 64位机器上的问题与临时解决方案
需求;logstash运行在SUSE,LINUX,PPC LINUX,AIX机器上,并监控文件发送日志到KAFKA中去, 问题:在AIX机器上,file插件总是报异常,无法完成数据的读取 NotImp ...
- Java基础知识笔记(一:修饰词、向量、哈希表)
一.Java语言的特点(养成经常查看Java在线帮助文档的习惯) (1)简单性:Java语言是在C和C++计算机语言的基础上进行简化和改进的一种新型计算机语言.它去掉了C和C++最难正确应用的指针和最 ...
- Java Generics and Collections-2.2
2.2 Wildcards with extends 前面介绍过List<Integer>不是List<Number>的子类,即前者不能替换后者, java使用? extend ...
- 常用算法——排序(三)
希尔排序法 希尔排序又称为缩小增量排序,也属于插入排序类的算法,是对直接插入排序的一种改进. 基本思想就是:将需要排序的序列划分为若干个较小的序列,对这些序列进行直接插入排序,通过这样的操作可使用需要 ...
- js获取键盘按下的键值event.keyCode,event.charCode,event.which的兼容性
js获取键盘按下的键值有event.keyCode,event.charCode和event.which 其中: 谷歌浏览器对event.keyCode,event.charCode和event.wh ...
- C# Winform程序把引用的dll放到指定目录
如果项目引用了很多dll,发布的时候放同一目录会很乱,这时候可以用privatePath后面指定搜索的dll文件夹,多个用;分隔 另外,发现在配置文件夹中 configSource 也是可以指定目录的 ...
- Nginx负载均衡实践之一:基本实现
由于现在的网站架构越来越大,基于互联网的用户也是日渐增长,所以传统的单机版服务器已经渐渐不能适应时代发展的需要.最近在和其他企业接触的过程中,发现对于互联网的经验尤为看重,所谓的互联网经验,其实就是指 ...
- React业务实践
总结自:http://reactjs.cn/react/docs/thinking-in-react-zh-CN.html 当接到一个需求时,如何用react来实现? 以下几个步骤做参考. 第一步:把 ...
- 查看struct或class的内存布局
适用于VC编译器(Visual Studio) 附加选项: /d1 reportSingleClassLayout[foo] 例如CItem(注意后面没有空格) /d1 reportSingleCla ...