- 字符编码是对字符数据编解码的方式
- 常用的字符编码有:UTF-8、UTF-16、GDB2312、Unicode等
- 我们需要知道,对于任何一个屏幕上显示出来的文字,其最底层一定是一串二进制数值表达的值;不同的值在同一个编码集中表示不同的文字,相同的值在不同编码集中可能表示不同的含义
- 一个完整的字符编码集是文字显示与其对应底层值的一一映射;说白了,一个编码集需要定义一个值对应的是哪个文字(这就是字符的编解码方式),还要提供接口对文字的显示进行定义
这样在程序编写时就有可能会出现问题
- 源文件用不同的编码方式编写,会导致执行结果不一样
比如,我在程序文件中编写如下代码,采用utf-8编码集
int main(int argc, char **argv)
{
printf("hello world\n");
return 0;
}
在编译后在只支持UTF-16的机器上运行,这样输出的就不是”hello world”,而是一段乱码
- 简单地说,显示乱码的出现最根本的原因的编码与解码采用了不同的字符编码集,而解码如果不兼容编码(包含关系)就一定会出现错误的结果
- 从一个系统整体的角度来看,无论输入什么,在输出端采用不同的处理手段是会得到不同结果的(不同的解码方式相当于将采用了不同的系统来处理输入)
那么要怎样解决可能出现的乱码问题呢?
可以在编译时指定字符集
-finput-charset=charset 表示源文件的编码方式, 默认以UTF-8来解析 -fexec-charset=charset 表示可执行程序里的字时候以什么编码方式来表示,默认是UTF-8
另一种方法是可以在具有多种字符集、且能自适应字符编码集的机器上运行(可以自动识别文字采用什么编码、从而采用对应解码)
- 个人理解是-finput-charset=charset设定源文件编码方式的意思是如论编写源文件时用的是什么字符编码,在指定charset后都转换成该charset来存储(实际保存的字符编码值是按指定的charset来的)
点阵字库HZK12、HZK16、HZK24、ASC12、ASC16
- 将制作好的字模放到了一个个标准的库中,这就是点阵字库文件
- 一般使用16*16的点阵宋体字库
- 16*16是每个汉字在纵、横各16个点的区域内显示
- 汉字库种类繁多,但都是按照区位的顺序排列的
- 前一个字节为该汉字的区号,后一个字节为该字的位号。每一个区记录94个汉字,位号则为该字在该区中的位置。
- 汉字在汉字库中的计算公式为:94*(区号-1)+位号-1
- 区位号是从1开始的,而数组是从0开始的
- HZK24系列是2424的点阵字库,每字模占用324字节
- 如果你按照HZK16的显示方法的话,你会看到字被放倒了
- 因为这类字库是为打印机设计的,为了打印的方便便将字模都放倒了
- 使用时,只需将字模的位信息纵横转置显示即可 ```c char mat[24][3] //一个字模的数组
//转置输出 for(i=0;i<24;i++) for(j=0;j<24;j++) if((0x80>>i%8)&mat[j][i/8]) /转置显示/ putpixel(j+x,y+i,color); / (0x80>>i%8)&mat[j][i/8] / 0x80 —> 0b1000 0000 一共8位 0x80>>i%8 ==> 0x80>>(i%8) 0x80右移0到7位,具体用意暂未知 (运算符%优先级高于>>) mat[j][i/8] 值是否为0
- 字库HZK12,虽然属于标准字库类型,但如果你将它的字模当作12*12位计算的话,根本无法正常显示汉字
- 因为字库设计者为了使用的方便,字摸每行的位数均补齐为8的整数倍,于是实际该字库的位长度是16*12,虽然每行都多出了4位,但这4位都是0(不显示),并不影响显示效果。
- HZK16字库是符合GB2312标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。
- HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的
- 如何在HZK16文件中找到它对应的32个字节的字模数据
- 一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号
- 区码:区号(汉字的第一个字节)-0xa0 (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)
- 位码:位号(汉字的第二个字节)-0xa0
- <br />
hzk汉字点阵
```c
int i,j,k;
unsigned char incode[3]="我"; // 要读出的汉字
unsigned char qh,wh;
unsigned long offset;
// 占两个字节, 取其区位号
qh = incode[0] - 0xa0;/ /获得区码
wh = incode[1] - 0xa0; / /获得位码
offset = (94(qh-1)+(wh-1))32; / 得到偏移位置 /
FILE *HZK;
char mat[32];
if((HZK=fopen("hzk16", "rb")) == NULL)
{
printf("Can't Open hzk16\n");
exit(0);
}
fseek(HZK, offset, SEEK_SET);
fread(mat, 32, 1, HZK);
//显示
for(j=0;j<16;j++)
for(i=0;i<2;i++)
for(k=0;k<8;k++)
if(mat[j][i]&(0x80>>k)) /测试为1的位则显示/
{
printf("%s",'#');
}else{ printf("%s",'-');
}
fclose(HZK);
fclose(fp);