title: 字符编码存储
date: 2019/02/26 23:31:59
toc: true
字符编码存储
字符编码查看
- 可以使用
notepad++
更改编码方式,然后用hex
查看 - 用
Ue
的话有快捷键ctrl+H
中的gbk编码是D6D0
,unicode的编码是4E2D
utf8的解码很简单,我们以E4 B8 AD
来解析.
对于n
字节的符号(n > 1
),第一个字节的前n
位都设为1
,第n + 1
位设为0
,后面字节的前两位一律设为10
。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
1110 0100 , 1011 1000 , 1010 1101
xxx 表示3个字节表示unicode
x 这个表示长度结束符号
开始编码
字体
一个文字,怎么显示?通过一个编码,找到具体的字模来达到具体的显示(点阵,公式等)
所以一个字体应该包括了字符编码和字体显示点阵数据
代码测试
我们写下这样一句
char * str_put="123中";
这个里面到底是怎么存储的呢?实际上默认是按照代码文件的格式存储的.
#include <stdio.h>
int main(int argc, char ** argv)
{
unsigned char * str_put="123中";
unsigned char * pt=str_put;
while(*pt)
{
printf("%02x ",*pt);
pt++;
}
printf("
");
return 0;
}
测试保存不同的编码,我在保存u16编码的时候,无法编译过去
[2019-02-26 21:57.29] /mnt/d/test_encode
[layty.layty-PC] ➤ gcc -o utf8 utf8.c
───────────────────────────────────────────────────────
[2019-02-26 21:59.32] /mnt/d/test_encode
[layty.layty-PC] ➤ ./utf8.exe
31 32 33 e4 b8 ad
[layty.layty-PC] ➤ ./ansi.exe
31 32 33 d6 d0
为什么?
其实是编码为gbk的时候,没有被gcc检测出错误,但不一定每次都能通过的.
指定编码的理解
man gcc
查找 charset
// 输入文件编码 默认以utf-8编码
-finput-charset=charset
//生成的可执行程序的编码
-fexec-charset=charset
-fwide-exec-charset=charset
-finput-charset=GBK
-fexec-charset=UTF-8
GBK
UTF-8
UTF-16BE
UTF-16LE
理解
这里的指定文件编码应该这么理解
-
假设现在我们有一个
char a="中";
文件的编码是GBK -
gbk
是兼容asc编码的,所以代码上一些其他的文字读取下来是没什么问题的,比如#include xxx
-
文件的具体的二进制实际上是已经定死的,也就是说你保存为GBK的时候,存储的就是
d6 d0
-
这个时候指定输入文件为
gbk
,则解码d6 d0
,我觉得这里内部会有一个转换为unicode
编码的中间文件 -
然后如果我们不指定输出文件的格式,则默认就是utf8,也就是将
d6 d0
当作utf8
,输出- 这个时候如果指定编码,我们再去转换这个中间文件的编码到指定的编码,默认还是utf8,所以输出还是
d6 d0
- 这个时候如果指定编码,我们再去转换这个中间文件的编码到指定的编码,默认还是utf8,所以输出还是
原始文件=按照-finput-charset=charset
读取>按照-fwide-exec-charset=charset
重新编码新的文件
- 所以如果我们指定输入文件格式为gbk的时候,他能正确解码
d6 b0
,转换成正确的unicode
码,然后你就需要指定输出文件的编码才能打印出你想要的了
比如存在如下代码
char *s = "中国";
printf("raw char[] is :");
for(i=0;i<10;i++)
printf("%x ",(*(s+i)&0xFF));
输入 | 输出编码 | 打印 |
---|---|---|
utf8 | utf8 | d6 d0 b9 fa |
utf8 | gbk | 报错 |
gbk | utf8 | e4 b8 ad e5 9b bd |
gbk | gbk | d6 d0 b9 fa |
如果文件是utf8编码的,则
输入 | 输出编码(实际raw的存储的二进制) | 打印 |
---|---|---|
utf8 | utf8 | e4 b8 ad e5 9b bd |
utf8 | gbk | d6 d0 |
gbk | utf8 | 报错 |
gbk | gbk | 报错 |
下面的代码以不同的编码保存,但是可以输出相同的结果
char *s="中国";
char buf[10];
printf("this file is encoding by gbk
");
g2u(s, strlen(s), buf, sizeof(buf));
printf("raw char[] is :");
for(i=0;i<10;i++)
printf("%x ",(*(s+i)&0xFF));
printf("
");
book@100ask:~/stu/code$ gcc -finput-charset=GBK -fexec-charset=GBK gbk_show.c
book@100ask:~/stu/code$ ./a.out
this file is encoding by gbk
raw char[] is :d6 d0 b9 fa 0 74 68 69 73 20
utf8 char[] is :e4 b8 ad e5 9b bd 0 0 0 0
book@100ask:~/stu/code$ gcc -fexec-charset=GBK utf8_show.c
book@100ask:~/stu/code$ ./a.out
this file is encoding by gbk
raw char[] is :d6 d0 b9 fa 0 74 68 69 73 20
utf8 char[] is :e4 b8 ad e5 9b bd 0 0 0 0
这样可以将gbk编码的文件编译成utf8编码的执行文件
book@100ask:~/stu/code/yy$ gcc -finput-charset=GBK -fexec-charset=UTF-8 ansi.c
book@100ask:~/stu/code/yy$ ./a.out
31 32 33 e4 b8 ad
但是依然无法解决utf16编码的,后来查找原因有说该是<stdio.h>
这个文件不是utf16
编码导致的,尝试删除这个文件,去除printf
后依然无法编译
文件编码转换
在搜索的时候发现可以使用iconv
来转换文件,使用iconv -l
能够列出字符集
iconv -f UTF-16BE -t UTF-8 -o ff.c utf16-big.c 确实转换了格式拿到win7下查看
然而我先转换为 UTF-16BE
,再编译这个文件依然过不去
iconv -t UTF-16BE -f UTF-8 -o ff.c utf8.c
book@100ask:~/stu/code/yy$ gcc -finput-charset=UTF-16BE -fexec-charset=UTF-8 -o -o aa ff.c
所以我觉得可以先将文件转换为utf-8
,再来编译