浅谈C/C++语言中char与中文编码字符存储

前几天数据结构课,老师作业让实现支持中文的 Huffman Coding...
因为,中文字符常用的少说也有几千个,所以权值表肯定是要只索引文本中出现的字符了。
这就涉及到中文字符存储的问题。

编码

首先我们要知道, ASCII 表中 0-127 用来显示现代英语,而 C/C++(clang) 中的 char 是 signed char,正数部分只有 0-127,所以中文想要存储,就只能用负数部分了。

在 UTF-8 中一个汉字占3字节,而在 GBK 中一个字符占2个字节。方便起见本文主要讨论 GBK 编码下的中文,UTF-8同理。

字节

既然中文占两个字节,显然只有一个字节(8位)的char是装不下了,必须另寻它处。这里我们可以选择两个字节的 short 来存储。

默认情况下,一个汉字是通过两个值为负数的 char 来进行存储的。所以我们可以通过位运算来将这两个 char 拼接到一起装在 short 中来进行存储。

char a,b;
short c;
c = a;
c <<= 8;
c |= b;

因为左移操作会在移动后补0,所以我们可以通过左移后按位或来实现拼接。但这里存在一个问题,char 的值是负的,其存在内存中的编码为补码,此时当只有8位的 char 和16位的 short 进行操作时,计算机会将 char 补上8个1,来将 char 转换为16位。显然按位或操作后 short 的高位将永远是 0xFF 即-1。

解决的方法有很多,只要保证类型转换后高位补0即可。比如按位取反,因为字符不做运算,所以我们可以不考虑这么操作后数值上的意义,我们需要的仅仅只是骗过计算机让它认为这是个正数,进而在类型转换时补0来实现存储罢了。输出时再次取反即可。

char a,b;
short c;
c = a;
c <<= 8;
c |= ~b;

输出

char d,e;
d = c>>8;
e = ~c;    //类型转换时会自动截断,丢弃高8位
printf("%c%c",d,e);
Tags:数据结构
上一篇
没有啦~

添加新评论