C语言向屏幕上写数据的最简单和最快的方法是什么?
向屏幕上写数据的最简单的方法是什么?
C语言包含了大约几百个向屏幕上写数据的函数,很难决定在某一时刻最适合用哪一个函数来向屏幕上写数据。许多程序员只是简单地选择一个或两个打印函数,并且以后只使用这些函数。这是一种可以接受的编程风格,尽管这样的程序员也许不是总能写出最好的代码。一个程序员应该做的就是把每个打印函数的设计目的和最佳用法都回顾一遍,这样,当他需要向屏幕上打印数据时,他就能选出最佳的函数,甚至还可以自己编写一些打印函数。
要成为一个真正熟练的程序员,第一步要做的工作的一部分就是学会正确地使用标准C语言库中的打印函数。让我们仔细地分析一下其中的几个函数。
printf(<format string>,variables);
printf()是使用最广泛的打印函数。在把文本输出到屏幕上时,有些程序员只使用这个函数。尽管如此,该函数的设计目的只是用来把带格式的文本打印到屏幕上。实际上,“printf"是“print formatted(带格式打印)”的缩写。带格式的文本是指文本中不仅仅包含写到代码中的字符串,还包含由程序动态生成的数字、字符和其它数据;此外,它的内容可以按一种特定的方式显示,例如,它可以按所指定的小数点前后的位数来显示实数。正是由于这个原因,所以printf()函数是不可缺少的!
那么,为什么有时又不使用printf()呢?这里有几个原因。
第一个原因是程序员想更清楚地表达他的意图。程序员可能只对printf()函数提供的诸多功能中的一小部分感兴趣,在这种情况下,他可能想使用只提供这一小部分功能的那个函数,例如:
putchar(char);
该函数的作用是把一个字符送到屏幕上。如果你只需做这部分工作,那么它是十分合适的。除此之外,它就不见得有什么好处了。然而,通过使用这个函数,你就能非常清楚地表达相应的那部分代码的意图,即把单个字符送到屏幕上。
puts(char*);
该函数的作用是把一个字符串写到屏幕上。它不能象printf()一样接受额外的数据,也不能对传递过来的字符串加以处理。同样,通过使用这个函数,你就能非常清楚地表达相应的那部分代码的意图。
程序员不使用printf()的第二个原因是为了提高程序的执行效率。printf()函数的额外开销太多,也就是说,即使是进行一次简单的操作,它也需要做大量的工作。它需要检查传递过来的字符串与格式说明符是否匹配,还需要检查传递过来的参数个数,等等。上面提到过的另外两个函数没有这些额外的开销,因此它们可以执行得非常快。这个因素对大多数向屏幕上写数据的程序来说并不重要,但是,在处理磁盘文件中的大量数据时,它就显得很重要了。
不使用printf()的第三个原因是程序员想减小可执行程序的大小。当你在程序中使用了标准C函数时,它们必须被“连接进来”,也就是说,它们必须被包含进所生成的可执行文件中。对于象putchar()和puts()这样简单的打印函数,对应的程序段是很短的,而对应于printf()的程序段却相当长——特别是因为它必然要包含前两个函数。
第二个原因可能是最不重要的一个原因,然而,如果你在使用静态连接程序,并且想保持较小的可执行文件的话,那么这就是一项重要的技巧了。例如,尽可能减小TSR和其它一些程序的大小是很值得的。
无论如何,程序员都应根据自己的目的来选择需要使用的函数。
向屏幕上写文本的最快的方法是什么?
通常,你不会过分关心程序写屏幕的速度。但是,在有些应用中,需要尽可能快地写屏幕,这样的程序可能包括:- 文本编辑器。如果不能很快地写屏幕,则由用户输入文本所造成的屏幕滚动和其它有关操作可能会显得太慢。
- 活动的文本。在同一区域快速地打印字符,是获得动画效果的一种常用手段,如果不能快速地把文本打印到屏幕上,那么动画就太慢了,视觉效果就不会好。
- 监视器程序。这样的程序要连续地监视系统、其它程序或硬件设备,它可能需要每秒在屏幕上打印多次状态的更新信息,而通过标准c库函数实现的屏幕打印对这样的程序来说很可能显得太慢。
那么,在这些情况下应该怎么办呢?有三种办法可以加快程序写屏幕的速度:选用额外开销较小的打印函数;使用提供了快速打印功能的软件包或函数库;跳过操作系统,直接写屏幕。下面将按从简到繁的顺序分析这几种办法。
1、选用额外开销较小的打印函数
有些打印函数的额外开销比别的打印函数要多。“额外开销”是指与其它函数相比,某个函数必须做的额外工作。例如,printf()的额外开销就比puts()多。那么,为什么会这样呢?
puts()函数是很简单的,它接受一个字符串并把它写到显示器屏幕上。当然,printf()函数也能做同样的工作,但它还要做大量其它的工作——它要分析送给它的字符串,以找出指示如何打印内部数据的那部分特殊代码。
也许你的程序中没有特殊字符,而且你也没有传递任何这样的字符,但不幸的是,printf()无法知道这一点,它每次都必须检查字符串中是否有特殊字符。
函数putch()和puts()之间也有一点微小的差别——在只打印单个字符时,putch()的效果更好(额外开销更少)。
遗憾的是,与真正把字符写到屏幕上所带来的额外开销相比,这些C函数本身的额外开销是微不足道的。因此,除了在一些特殊情况下之外,这种办法对程序员不会有太大的帮助。
2、使用提供了快速打印功能的软件包或函数库
这可能是有效地提高写屏速度的最简单的办法。你可以得到这样的一个软件包,它或者会用更快的版本替换编译程序中固有的打印函数,或者会提供一些更快的打印函数。
这种办法使程序员的工作变得十分轻松,因为他几乎不需要改动自己的程序,并且可以使用别人花了大量时间优化好了的代码。这种办法的缺点是这些代码可能属于另一个程序员,在你的程序中使用它们的费用可能是昂贵的。此外,你可能无法把你的程序移植到另一种平台上,因为那种平台上可能没有相应的软件包。
不管怎样,对程序员来说,这是一种既实用又有效的办法。
3、跳过操作系统,直接写屏幕
由于多种原因,这种办法有时不太令人满意。事实上,这种办法在有些计算机和操作系统上根本无法实现。此外,这种办法的具体实现通常会因计算机的不同而不同,甚至在同一台计算机上还会因编译程序的不同而不同。
不管怎样,为了提高视频输出速度,直接写屏是非常必要的。对全屏幕文本来说,你可能可以每秒种写几百屏。如果你需要这样的性能(可能是为了视频游戏),采用这种办法是值得的。
因为每种计算机和操作系统对这个问题的处理方法是不同的,所以要写出适用于所有操作系统的程序是不现实的。下文将介绍如何用Borland c在MS-DOS下实现这种办法。即使你不使用这些系统,你也应该能从下文中了解到正确的方法,这样你就可以在你的计算机和操作系统上写出类似的程序了。
首先,你需要某种能把数据写到屏幕上的方法。你可以创建一个指向视频缓冲区的指针。在MS-DOS下使用Borland C时,可以用下述语句实现这一点:
char far*Sereen=MK_FP(0xb800,Ox0000);
far指针所指向的地址并不局限于程序的数据段中,它可以指向内存中的任何地方。MK_FP()产生一个指向指定位置的far指针。有些其它的编译程序和计算机并不要求区分指针的类型,或者没有类似的函数,你应该在编译程序手册中查找相应的信息。
现在,你有了一个“指向”屏幕左上角的指针。只要你向该指针所指向的内存位置写入若干字节,相应的字符就会从屏幕的左上角开始显示。下面这个程序就是这样做的:
#include<dos.h>
main()
{
int a:
char far*Screen=MK_FP(Oxb800。Ox0000):
for(a=0;a<26;++a)
sereen[a*2]='a'+a:
return(O);
}
该程序运行后,屏幕顶端就会打印出小写的字母表。
你将会发现,字符在视频缓冲区中并不是连续存放的,而是每隔一个字节存放一个。这是为什么呢?这是因为一个字符虽然仅占一个字节,但紧接着它的下一个字节要用来存放该字符的颜色值。因此,屏幕上显示的每个字符在计算机内存中都占两个字节:一个字节存放字符本身,另一个字节存放它的颜色值。
这说明了两点:首先,必须把字符写入内存中相隔的字节中,否则你将会只看到相隔的字符,并且带有古怪的颜色。其次,如果要写带颜色的文本,或者改变某个位置原有的颜色,你就需要自己去写相应的颜色字节。如果不这样做,文本仍然会按原来的颜色显示。每个描述颜色的字节既要描述字符的颜色(即前景色),又要描述字符的背景色。一共有16种前景色和16种背景色,分别用颜色字节的低4位和高4位来表示。
这部分内容对一些缺乏经验的程序员来说可能有点复杂,但还是比较容易理解的。只要记住有16种颜色,其编号范围是从。到15,要得到颜色字节的值,只需把前景色的值和背景色值的16倍相加即可。下面这个程序就是这样做的:
#include<stdio.h>
main()
{
int fc,bc,c;
scanf("%d %d",&fc,&bc);
printf("Foreground=%d,Background=%d,Color=%d\n",
fc,bc,fc+bc*16);
return(0);
}
你可能会同意这样一点,即在大多数情况下,在整个程序中都由程序员明确地写出要送到屏幕上的字节是不现实的。最好是编写一个把文本写到屏幕上的函数,然后频繁地调用这个函数。让我们来分析一下如何构造这样一个函数。
首先,你需要问一下自己:“我需要向这个通用打印函数传递一些什么信息?”作为初学者,你可以传递以下这些信息:
- 要写到屏幕上的文本;
- 文本的位置(两个坐标值)
- 字符的前景色和背景色(两个值)
现在,你知道了需要把什么数据传递给该函数,因此你可以按以下方式来说明这个函数:
void PrintAt(char*Text,int x,int y,int bc,intfc)
下一步你需要计算要打印的文本的颜色字节值:
int Color=fc+be*16:
然后需要计算文本指针的起始位置:
char far*Addr=&screen[(x+y*80)*2];
需要特别注意的是,为了把文本写到正确的位置上,你必须把偏移量乘以2。此外,使用该语句的前提是在程序中已经定义了变量Screen。如果该变量还未定义,你只需在程序中相应的位置插入下述语句:
char far*Screen=MK_FP(0xb800,0x0000);
现在,准备工作都完成了,你可以真正开始向屏幕上写文本了。以下是完成这项任务的程序段:
while(*Text)
{
*(Addr++)=*(Text++);
*(Addr++)=Color;
}
在还未写完全部文本之前,这段代码会一直循环下去,并把每个字符和对应的颜色写到屏幕上。
以下这个程序中给出了这个函数完整的代码,并且调用了一次该函数。
#include(dos.h>
/*This is needed for the MK—FP function*/
char far*Screen=MK_FP(Oxb800,Ox0000):
void PrintAt(char*Text,int x,int y,int bc,int fc)
{
int Color=fc+bc*16;
char far*Addr=&screen[(x+y*80)*2];
while(*Text)
{
*(Addr++)=*(Text++);
*(Addr++)=Color;
}
}
main()
{
int a:
for(a=1;a<16:++a)
PrintAt("This is a test",a,a,a+1,a);
return(0);
}
如果比较一下这个函数和固有的打印函数的执行时间,你会发现这个函数要快得多。如果你在使用其它硬件平台,你可以用这里所提供的思路来为你的计算机和操作系统编写一个类似的快速打印函数。