在许多C程序设计中,要用到汉字进行提示或人机交互,而现行的Turbo C集成开发环境不是的,如何编制能显示汉字的C程序呢? 下面的方法可以帮你在西文环境下显示汉字。这种方法是调用中文汉字库进行汉字显示。国家标准规定:汉字库分94个区,每个区有94个汉字(以位作区别),每个汉字在汉字库中有确定的区和位编号,这就是汉字的区位码。每个汉字在库中是以点阵字模形式存储的,一般采用16×16点阵(32字节)、24×24点阵(72字节),每个点用一个二进制位(0或1)表示,对应在屏幕上显示出来,就是相应的汉字。 由于在中文环境下,输入的是汉字的内码,我们必须将之转换成区位码,算出偏移量,从字库中到对应的汉字,将其字模显示即可。
内码转换成区位码方法如下:
qh=c1-0x10 wh=c2-0xa0
其区位码就是:
qw=qh*0xff+wh
该汉字在字库中离起点的位置是: 参与式教学
offset=(94*(qh-1)+(wh-1))*32L
程序例:
*/
美国种族简史#include<graphics.h>
#include<stdio.h>
#include<fcntl.h>
#include<io.h>
#include<stdlib.h>
#include<conio.h>
#define ROW 1 /*纵坐标放大倍数*/
#define COL 2 /*横坐标放大倍数*/
void main()
{
int x,y;
char *s="汉字显示程序";
FILE *fp;
char buffer[32];/*buffer用来存储一个汉字*/
register m,n,i,j,k;
unsigned char qh,wh;
猎德小学
unsigned long offset;
int gd=VGA,gm=VGAHI;
initgraph(&gd,&gm,"");
if((fp=fopen("hzk16","rb"))==NULL)
{printf("Con't open hzk16,Plase add it");getch();closegraph(); exit(0);}
x=20;y=100;
while(*s){
qh=*(s)-0xa0;
wh=*(s+1)-0xa0;
offset=(94*(qh-1)+(wh-1))*32L;
fseek(fp,offset,SEEK_SET);
fread(buffer,32,1,fp);
for(i=0;i<16;i++)
for(n=0;n<ROW;n++)
for(j=0;j<2;j++)
for(k=0;k<8;k++)
for(m=0;m<COL;m++)
if(((buffer[i*2+j]>>(7-k))&0x1)!=NULL) putpixel(x+8*j*COL+k*COL+m,y+i*ROW+n,GREEN);
s+=2;
x+=30;
限额设计}
getch();
closegraph();
双宿主机}
/*关于以上程序的有
关说明:
英文和汉字在计算机中都是以数字表示的,保存时每个英文字符使用一个字节,每个汉字字符使用两个字节——这里只保存的是字符在其所属的字符集中的位置,不是显示字形信息。对于英文来说,我们所说的某字符的ASCII码实际上就是指这个,BASIC语言中有个ASC(S$)函数,为什么C语言中没有呢?C语言与底层接近,它对字符的解释就是一个8bit的数(类型为BYTE,范围0-255),字符串的解释就是一个字节数组!
英文的字符集比较小,26个字母,大小写,标点符号全算上,也没有256个,所以一字节足够了——实际上ASCII最初只定义了128个字符,编号从0~127,从二进制上来看8个bit只用了7个,最高位上的一个bit没有使用,恒为零。而咱们的汉字可就太多了,生活中常见的就有上万个,国家(大陆)费了好大劲才筛选了6千多个最常用的汉字编了一个GB2312字符集,这就是我们最常用的汉字编码标准,俗称GB码(其实这个字符集还是小了点,象“骉”“喆”等字就不在其中,现在制的GBK集和GB18030集才算够用了),保存在文件中的汉字就是这个汉字在GB2312集中的编号。可是事情没有这么简单,汉字和英文都在内存里以字节形式待着,彼此长得也差不多,可是如果你看到连续的两个字节到底是一个汉字还是两个英文字符呢?所以实际上汉字的内码必须要和英文有所区别,除非我们不用英文才能不考虑兼容它。前面说了,ASCII码中还有一个最高位没有用,这就是一个很好也是唯一的标志——最高位为0的为英文字符,最高位为1的为汉字,用数学来说就是这个数小于等于127是
英文,大于127就是汉字。
上面程序中有以下行
qh=*(s) - 0xa0; //汉字区位码
wh=*(s + 1) - 0xa0;
区位码是一个方法,用来将GB2312字集这个长的一维数组改写成二维数组,从而使之能在一个字节剩下的有限表达空间(128-255)里能以两个字节来记录一个汉字,前者用来表示行,后者用来表示列——这就是汉字的区码和位码。我们可以计算出,两个字节可以表示多少不同汉字:sizeof(BYTE gb[128][128])=16384,但在GB2312标准中的定义更保守:BYTE gb2312[94][94],并规定汉字内码中的每个字节必须大于161,也就是区码为1内码为161,位码为1内码为161。我们要得到真实的二维数组下标必须减去161,这里上面的两句只减了160,下面还有一句又减了1:
offset=(94*(qh-1)+(wh-1))*32L; //计算该汉字在字库中偏移量
这句在意思上其实可以分为两句:
hz_offset=94*(qh-1)+(wh-1); //将二维数组转为一维数组,
专利权的保护范围
由行(区)和列(位)来计算出一维下标
offset=hz_offset*32L; //计算该汉字在字库中偏移量
不得不说明一下,前面所提到的均是指汉字的表意功能在计算机的表示方法,现在到了汉字的显示了。汉字除非作为一种图形在显示器上,不然没有人能看明白,这是汉字的图形表示。我们的思考和书写不同也是这个道理。
装有中文系统的计算机中都有一套或几套字库,字库实际上是个图库,里面按GB2312集中汉字的顺序保存着每个汉字的图形。不同的字库中相同的汉字的图形也不同,有书写风格不同——字体变化,有精度不同——字号大小,实现方法不同——点阵和矢量。UCDOS的HZK16是一个宋体16点阵字库,这个字库的字形刚好能够清晰显示在屏幕上,是DOS时代最常用的显示字库。HZK16中的每个汉字是一个以16×16点阵图形,每个点只有两种状态(有、无)占一个bit,因此共占16×16÷8=32 BYTES。那么HZK16内部也可以理解为BYTE [94*94][32]或者BYTE[94*94*32]。上面用了32L是因为94*94*32已经超过unsigned int(16bit)的表示范围了,必须改用long(32bit)。
在这32个字节中,第1字节表示16*16点阵的第一行的左边8个点,方向是由高位到低位,如0x71表示○●●●○○○●;第2字节表示16*16点阵的第一行的右边8个点;第3字节……,同上。我们所要做的,就是判断各bit为1,然后在屏幕相应的地方画点了。
if (((buffer[i*2+j]〉〉(7-k))&0x1)!=NULL)
putpixel(x+8*j*COL+k*COL+m,y+i*ROW+n,GREEN);
好了,就说这么多了。另外现在的DOS汉字系统已经很完美了,基本上已经不用我们的程序自己管显示了,而且读磁盘字库显示汉字的速度很慢,可能只在很不常见的地方才用这个