【首先简单理解几种编码】
ascii是ansi标准,包含128个字符(7 bits)
我们说的ansi编码,通常特指windows平台的一种ascii扩展码,他将ascii码扩展到8bits,增加了0x80-0xff共128个字符。在cjk(chinese japanese korean)系统中,ansi还常常指代包括多字节内码的编码。不难看出,所谓ansi编码,就是一种未经国际标准化(也没办法标准化,因为扩展部分的内码存在交集)的兼容ascii编码的,非unicode字符集编码
GB 2312 或 GB 2312-80 最早中国字符编码集,就是GB国标,中国国家标准简体中文字符集,约6763 个汉字,其中一级汉字 3755 个,二级汉字 3008
GBK 即汉字内码扩展规范,就是GBK国标扩,兼容GB 2312,约 21886 个汉字和图形符号,【包含BIG5 中的全部汉字】
BIG5 台湾、香港地区的一个繁体字编码方案
GB 18030,最终汉字编码,与GB 2312-1980 和 GBK 兼容,共收录汉字70244个
【搞清GB 18030,GBK,GB 2312总体关系,都是【双字节】】
Unicode,统一码,包括世界上所有字符【双字节】,【与上面的汉字编码不兼容,不一致】
utf8是Unicode的具体一种实现方式,【变长编码】【一个汉字占3字节,字母占一个字节】,utf8的编码就是Unicode的编码,不过会变长处理后存储
【程序对字符编码的解释】
字符就是一串 unsigned char[] 数组,每一个char,表示一个字节,数字0-255
程序对字符编码的解释就是如何看待这一串unsigned char[] 数组表示的数字序列。编码只是规定数字序列表示的字符含义,程序看到的也只是具体的数字序列,
汉字不同编码:我 []内为16进制编码
GB2312编码:[CED2] BIG5编码:[A7DA] GBK编码:[CED2] GB18030编码:[CED2] Unicode编码:[6211] utf8编码:[6211] utf8实际存储格式[e68891]
中国windows的cmd默认使用gbk,代码页936
//printf输出汉字
//需要vs,文件--高级保存选项--编码,代码页936,保证 aa是gbk编码
#include <stdio.h>
int main()
{
unsigned char aa[] = "我";
unsigned char bb[] = {0xce,0xd2,'\0'};
//查看编码
for (int i = 0; i < strlen(aa); i++)
{
printf("%x\n", aa[i]);
}
printf("%s\n", bb);
return 0;
}
cmd切换代码页
chcp 65001 就是换成UTF-8代码页
chcp 936 可以换回默认的GBK
chcp 437 是美国英语
显示utf8汉字
////printf输出汉字
//需要vs,文件--高级保存选项--编码,代码页936,保证 aa是gbk编码
#include <stdio.h>
int main()
{
unsigned char aa[] = "我";
unsigned char bb[] = {0xe6,0x88,0x91,'\0'};
//打印的还是gbk编码
for (int i = 0; i < strlen(aa); i++)
{
printf("%x\n", aa[i]);
}
//输出utf8字符
printf("%s\n", bb);
return 0;
}
ctrl+f5 编译运行,看到gbk编码,和乱码
新开cmd窗口
chcp 65001
把生成的exe拖动cmd后,回车运行,看到utf8编码汉字
最后是unicode与utf8转换方法
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
----------------------+---------------------------------------------
0 <--> 0x7f | 0xxxxxxx
0x80 <--> 0x7FF | 110xxxxx 10xxxxxx
0x800 <--> 0xFFFF | 1110xxxx 10xxxxxx 10xxxxxx
0x10000 <--> 0x10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
汉字“我”,unicode:6211,二进制:0110 0010 0001 0001【一定要补全最前面的0,一共双字节16位】
填充到utf8编码,6211属于0x800 <--> 0xFFFF,所有需要三字节
1110xxxx 10xxxxxx 10xxxxxx (规则)
0110 001000 010001 (unicode编码,从右向左依次填充x)
--------------------------
11100110 10001000 10010001 (utf8实际存储编码)
处理器大小端对字符编码的影响
值0x11223344,机器字长,一个内存地址存储的逻辑值
存储方式:
大端:11|22|33|44
小端:44|33|22|11
低地址---》高地址
大端主要是与人看的一致
小端主要是与值得逻辑一致(低位在低地址)
intelcpu,是小端格式,wchar_t是双字节char
#include <stdio.h>
int main()
{
wchar_t *bb[] = {'a','b'};
//bb是2位数字,占4字节
printf("%d\n", sizeof(*bb));
只能打印出a
printf("%s\n", bb);
return 0;
}
【原因】
机器字长32位,所有小端格式是对32位高低转换
wchar_t 双字节 16位
wchar_t *bb[] = {'a','b'} 32位
逻辑上内存结构是:00000000 01100001 00000000 01100010 (00 97 00 98 十进制ascii码)
但是小端的存储是:01100001 00000000 01100010 00000000 (97 00 98 00 十进制ascii码)
printf读到的是小端存储的值,所有打印了a,下个字节是0,表示字符串结束