关于字符编码这个展开来说有太多东西了,这里主要是想说一说最常说的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)编码来表示呢?

如下程序:

  1. #include <stdio.h>
  2. int main()
  3. {
  4. char a1[] = "a";
  5. char b1[] = "b";
  6. char c1[] = "c";
  7. char a2[] = "我";
  8. char b2[] = "你";
  9. char c2[] = "他";
  10. printf("a1:%d——b1:%d——c1:%d\n", a1[0],b1[0],c1[0]);
  11. printf("a2:%x——b2:%x——c2:%x\n", a2[0],b2[0],c2[0]);
  12. printf("a2:%x——b2:%x——c2:%x\n", a2[1],b2[1],c2[1]);
  13. return 0;
  14. }

查看内存:

命令行输出结果为:

  1. a1:97——b1:98——c1:99
  2. a2:ffffffce——b2:ffffffc4——c2:ffffffcb
  3. 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个字节表示,常用于网络传速。

对于如下程序:

  1. #include <Windows.h>
  2. #include <stdio.h>
  3. #include <locale.h>
  4. int main()
  5. {
  6. wchar_t a1[] = L"a";
  7. wchar_t b1[] = L"b";
  8. wchar_t c1[] = L"c";
  9. wchar_t a2[] = L"我";
  10. wchar_t b2[] = L"你";
  11. wchar_t c2[] = L"他";
  12. wprintf_s(L"a1:%x——b1:%x——c1:%x\n", a1[0], b1[0], c1[0]);
  13. wprintf_s(L"我:%x——你:%x——他:%x\n", a2[0], b2[0], c2[0]);
  14. _locale_t lt = _get_current_locale();
  15. printf_s("\n之前代码页:%s\n", (lt->locinfo)->lc_category[0].locale);
  16. _wsetlocale(LC_ALL, L"chs");
  17. lt = _get_current_locale();
  18. wprintf_s(L"现在代码页:%s\n", (lt->locinfo)->lc_category[0].wlocale);
  19. wprintf_s(L"\na1:%x——b1:%x——c1:%x\n", a1[0], b1[0], c1[0]);
  20. wprintf_s(L"我:%x——你:%x——他:%x\n", a2[0], b2[0], c2[0]);
  21. return 0;
  22. }

查看内存:

程序运行结果为:

  1. a1:61
  2. 之前代码页:(null)
  3. 现在代码页:Chinese (Simplified)_People's Republic of China.936
  4. a1:61——b1:62——c1:63
  5. 我: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的更多相关文章

  1. ASCLL、Unicode和UTF-8编码的理解

    我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题. 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit) ...

  2. Python学习:基本概念

    Python学习:基本概念 一,python的特点: 1,python应用场景多;爬虫,网站,数据挖掘,可视化演示. 2,python运行速度慢,但如果CPU够强,这差距并不明显. 3,严格的缩进式编 ...

  3. python注释方法以及编码问题

    一.单行注释 在python中常使用"#"来进行单行注释,其快捷键为"ctrl+/",如果要对多行代码也就是代码块进行注释时,也可以选中多行按下 "c ...

  4. HTML基础学习笔记(2)

    HTML学习笔记(2) 1 head标签中的结构 编码结构:<meta charset="UTF-8"> charset---编码 ascll ansi Unicode ...

  5. html基础标签下

    1.1 单标签 ◆注释标签   ctrl+/ ◆水平线标签   <hr> ◆换行标签   <br> 1.2 双标签 ◆段落标签    <p></p> ◆ ...

  6. 2017年5月24日 HTML 基础知识(二)

    1 快捷方式:html:xt +tab   过渡XHTML html:xs+tab  严格XHTML !+tab  html5的标签结构 2.Charset   编码 <meta charset ...

  7. 老齐python-基础2(字符串)

    1.字符串 1.1索引和切片 索引: >>> lang = "study python" >>> lang[0] 's' >>> ...

  8. Microsoft SQL Server Transact-SQL

    Microsoft SQL Server Transact-SQL 1.SQL 1.1数据定义语言(DDL) create 创建数据库或数据库对象:alter 修改数据库或数据库对象:drop 删除数 ...

  9. python中文编码 - python基础入门(5)

    python到目前为止,一共有两个版本,分别是2.x和3.x版本,根据官方正式通知2020年停止对python更新和维护,距离今天还有110天左右,所以正在学习python的小伙伴应该暗中庆幸一波. ...

随机推荐

  1. [django]django+datatable简单运用于表格中

    使用datatable首先需要下载datatable文件,文件主要包括三个文件夹css,img,js相关文件,在django中如何配置呢? 首先需要在模板中引入datatable文件,格式如下: &l ...

  2. 【Python数据分析】Python3操作Excel(二) 一些问题的解决与优化

    继上一篇[Python数据分析]Python3操作Excel-以豆瓣图书Top250为例 对豆瓣图书Top250进行爬取以后,鉴于还有一些问题没有解决,所以进行了进一步的交流讨论,这期间得到了一只尼玛 ...

  3. codevs 1536 海战

    时间限制: 1 s  空间限制: 256000 KB  题目等级 : 白银 Silver 题目描述 Description 在峰会期间,武装部队得处于高度戒备.警察将监视每一条大街,军队将保卫建筑物, ...

  4. ffmbc——广播电视以及专业用途量身定制的FFmpeg

    做项目遇到针对于mpegts多节目流转码的问题,看遍了ffmpeg的参数都得不到解决办法,最后在雷神的博客中看到了ffmbc: 结果,还是没解决问题,但是看起来改改ffmbc的代码还是相对简单一些,抽 ...

  5. protobuf简介

    #1,简介 把某种数据结构的信息,以某种格式保存起来: 主要用于数据存储,传输协议格式. #2,优点 性能好 反观XML的缺点:解析的开销惊人,不适用于事件性能敏感的场合:为了有较好的可读性,引入一些 ...

  6. AppBox升级进行时 - Any与All的用法(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 属于某个角色的用户列表(Any的用法) 使用Subsonic,我们有两种方法获 ...

  7. manachor

    在原字符串每个字符间各插入一个未曾出现的字符,在字符串头插入另一个未出现的字符防止越界,求出的p[i]-1既为以i为中心的最长回文串的长度 void manacher(){ ,id; ;i<=n ...

  8. C语言与内存模型初探

    #include<stdio.h> #include<string.h> int main(){ long long int a = 2<<30; char str ...

  9. RecyclerView的使用(三)

    上个小结中介绍了如何使用RecyclerView显示不同的数据展示样式(瀑布流也是可以显示的,从GridView改就好) 本节来为RecyclerView的item添加监听事件. RecyclerVi ...

  10. [转]ExtJS之遍历Store

    原文地址:http://blog.sina.com.cn/s/blog_67cc6e7d0100ox6u.html ExtJS中,一般很少需要遍历Store,因为它的selectModel很好用,无论 ...