回 帖 发 新 帖 刷新版面

主题:[原创]看了下面的对比,还有人会用 TC 来编图形程序吗?

差不多每天都有关于 TC 的 graphics 库和 Bios 中断调用画图的问题,好象很多人着迷于用 TC 的 graphics 库和 TC 下的 Bios 中断调用画

图.为什么会这样呢? 我想原因可能在于他们认为 VC 和 Windows 的包装程度高,包装程度高的东西离低层的实现远,接口多,所以用 VC 的类库或 Windows 的 API 做的图形程序性能不如用 TC 的 graphics 库和 Bios 中断调用的图形程序.

老实说,我以前也以为用 VC 做的图形程序性能肯定比不上 TC 做的,但因为一直是做 Windows 程序,为了生产效率也就没有怎么用 TC 画过图,也没想过做个性能对比.

说到这, 真得感谢 wonsea 同志,是他给了我一个机会来纠正我的错误认识. wonsea 在前天的 《putimage 函数》那篇帖子里给出了他用 Bios 中断调用和 graphics 库做的一个鼠标程序, 当时他的程序有点小问题,我就调试了一下他写的程序,运行后我发现鼠标移动快一点时光标就跟不上了,当时我就产生了一个疑问:我在 windows 下写的那些图形程序要移动的对象更多,怎么 TC 的程序反而不如 VC 的程序呢?

于是我就用 Bios 中断调用写了如下一段程序:

//test.cpp
#include<stdio.h>

int main(void)
{
    union REGS  regs,regsa;
    
    regs.h.ah=0x0f;
    int86(0x10,&regs,&regsa);
    
    regs.h.ah=0x00;
    regs.x.ax=0x4f02;
    regs.x.bx=0x105;
    int86(0x10,&regs,&regs);

    struct time beginDraw,endDraw;

    gettime(&beginDraw);
    
    for(long j=0;j<1000;j++)
    {
        for(int i=0;i<600;)
        {
            regs.h.ah=0x0C;
            regs.h.al=60;
            regs.h.bh=0;
            regs.x.cx=j%800;
            regs.x.dx=i;
            int86(0x10,&regs,&regs);
            i++;
        }
    }
    
    gettime(&endDraw);
    getchar();
    
    regs.h.al=regsa.h.al;
    regs.h.ah=0;
    int86(0x10,&regs,&regs);
    
    printf("%hu:%hu\n",beginDraw.ti_sec,beginDraw.ti_hund);
    printf("%hu:%hu",endDraw.ti_sec,endDraw.ti_hund);

    getchar();
    
    return 0;
}

运行结果令我大吃一惊!我居然只看到一些线在屏幕的上半方乱跳!而且 beginDraw 和 endDraw 两个时间居然相差6.53秒,我开始以为是我设的参数 regs.x.bx=0x105 ( 这个参数对应的显示模式是 1024*768 的分辨率,256 色 ) 的问题,于是我把 0x105 改成了 0x104 ( 1024*768 分辨率, 16色),颜色 ( for循环中的参数 regs.x.al ) 取为 8 ,这下还好,总算画出来了,但也用了 6.53 秒, 而且我发现 0x105 和 0x104 都没意义! 因为 TC++3.0 的 int86 函数根本不支持那么高的分辨率.最后我把 0x104 改成了 0x102 ( 600*800 ,16 色 ) ,这下可以填满屏幕了,但同样花了6.53 秒.

天呀,这个速度在我的印象里比 Visual Basic 6 的 pset 方法还要慢的多, 于是我又用 Visual Basic 6 写了下面一段事件句柄:

Private Sub Form_Click()

  Dim i, j, beginTime As Integer
  
   beginTime = Second(Now)
   
   For i = 0 To 10000

       For j = 0 To 600
          PSet (i Mod 800, j)
       Next j
       
   Next i
   
   Me.Cls
   
   Print beginTime
   
   Print Second(Now)
          
      
End Sub

这一下清楚了,我用 Visual Basic 6 做 10 倍的工作,用的时间却只多 1/3 (VB 6 内嵌了真编译器,从那时起VB 6 就告别了解释语言的臭名声).而且编码简单,界面漂亮! VB 6 的 pset 方法都比 TC 的中断调用快 6 倍! 在我的印象中,VB 6 的 pset 方法比 VC++ 6 的 SetPixel ( 也是 windows API) 函数慢将近一半,于是我又用 VC++6 的 SetPixel 方法写了类似的一段 ( 篇幅所限,不帖了),又用 TC graphics 库的 putpixel 写了类似的一段, 结果证明:
      
   [color=0000FF]用 VC++6 或 Win API 函数 SetPixel 画点比用 Bios 中断调用快 10 倍!比 TC 的 putpixel 快 5 倍![/color]

为什么会这样呢?无疑是由于 TC 内嵌的限制太多, 缓冲设定和访问硬件的能力都不如现代编译器! 如果要在 graphics 库和 TC 相关库的基础上改进 TC 的图形库, 必须重写许多东西,其工作量之大,危险性之大让人不敢设想. 除非直接访问显示缓存,进一步加大缓冲区,否则 TC 画图速度无法与 VC 相比! 但你在 TC 中能做的 VC 中都能做( 比如内嵌汇编语言 ), 而且 VC 的起点比 TC 高的多,要想让 TC 在图形方面赶上 VC 的话,恐怕必须对 TC 编译器和缺省库做极大的改动,那还能称为 TC 吗? 幸好 TC 发展成了 Borland C++Builder .

由于VC++.Net2005 的 graphics 对象没有类似的画点函数 ( graphics画点实际上是用画框或画圆的办法画的,但我嫌这种画点方法慢就把 VC++6 中的 SetPixel 从新包装到了我的程序里,因而我在 VC++.Net2005 中的画点速度和 VC++6 差不多),所以我没有用VC++.Net2005 的 graphics 对象做上面的画点程序.

不过我用 VC++.Net2005 写了下面一段事件句柄以比较 VC++.Net2005 的 graphics 对象的 DrawLine 方法和 TC 的 line 函数的工作效率:

    private: System::Void Form1_Click(System::Object^  sender,
               System::EventArgs^  e)
             {
                 Graphics^ g=this->CreateGraphics();
                 
                 DateTime beginDraw=DateTime::Now;
                 
                 Pen^ lp=gcnew Drawing::Pen(Drawing::Color::Red);

                 for(int i=0;i<10000;i++)
                 {
                          g->DrawLine(lp,i%800,0,i%800,600);
                 }

                 DateTime endDraw=DateTime::Now;

                 Drawing::Font^ lf=gcnew Drawing::Font("宋体",20);
                 Brush^ b=Brushes::Blue;

                 g->DrawString(beginDraw.Second.ToString()+":"+
                     beginDraw.Millisecond.ToString(),lf,b,0,50);

                 g->DrawString(endDraw.Second.ToString()+":"+
                     endDraw.Millisecond.ToString(),lf,b,0,200);
                 

             }

对应的 TC 代码如下:

//testa.cpp
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>

int main(void)
{
   int gdriver = DETECT, gmode, errorcode;

   initgraph(&gdriver, &gmode, "");
   errorcode = graphresult();

   if (errorcode != grOk)
   {
      printf("Graphics error: %s\n", grapherrormsg(errorcode));
      printf("Press any key to halt:");
      getch();
      exit(1);
   }

   setcolor(RED);

   struct time beginDraw,endDraw;
   gettime(&beginDraw);

   for(int i=0;i<10000;i++)
      line(i%800,0,i%800,600);

   gettime(&endDraw);

   getch();
   closegraph();

   printf("%hu:%hu\n",beginDraw.ti_sec,beginDraw.ti_hund);
   printf("%hu:%hu\n",endDraw.ti_sec,endDraw.ti_hund);

   getch();

   return 0;
}

这两段代码的对比也挺有意思,VC++的代码短(包装度高),性能好(VC++用了1.09秒,TC用了4.56秒).

那些还在 Dos 下编图形程序的兄弟们,看了上面的对比,痛下决心,马上转到 VC++ 来吧!!!不要怕 VC++ 巨大的类库,VC++IDE 的智能化程度远比 TC 高,调试工具全面,编码效率高的多!



回复列表 (共16个回复)

11 楼

都15年过去了,大家还在用TC graphics.h,汗!不过不怪大家,我知道学校的教学手段估计跟不上时代的步伐。
当初我就是在8088上做tc图形毕业设计的。

12 楼

我的亲身感受:没有接触过DOS的人对windows 下许多概念是根本无法理解其本质的,他只知道这是什么,怎么用,但要让其知道他的原理及来龙去脉,简直太难了。

13 楼

好奇的问

DOS下最大支持多大的内存?

14 楼

两个可以比么???................

15 楼

[quote]我的亲身感受:没有接触过DOS的人对windows 下许多概念是根本无法理解其本质的,他只知道这是什么,怎么用,但要让其知道他的原理及来龙去脉,简直太难了。[/quote]
dos是独占系统,从这一方面讲,就不及windows,linux, unix等
你想搞清楚中断之类的,可以去把unix或者linux的源代码看看
我觉得dos系统过时了

16 楼

像素逐个绘制,本来就是效率非常低的做法。
我不知道80年代时是什么情况,但90年代初,这个做法已经不被商业的图形程序所接受。目前一般的做法是:把多个需要绘制的像素放到一个数组中,用一个函数就可以绘制许多像素。
这样做的好处:
1. 现在几乎所有的图形硬件都可以同时处理多个相邻的像素。如果每次只绘制一个像素的话,无法利用这个优势,效率会成倍下降。
2. 若每秒绘制60次,每次绘制1024*768个像素,每绘制一个都调用一次函数,这个开销可不小。

几种图形系统比较“绘制单个像素”的效率,正如几个拳击手来比较小脚趾的力量一样,没什么意义。拳击手就应该比拳头,而图形系统就应该比“绘制整幅图象”的效率。



早些时候(1989年)出了一个被称为VESA的标准,在DOS中也可以提供高分辨率的真彩色显示。Jig在5楼提到的33号中断似乎就是属于VESA标准的。但是说实在的,在现代显卡中,“绘制像素”早就不是什么研究课题,图形程序已经进入“可编程”时代,随着越来越多的功能被图形硬件实现,纯粹的“绘制像素”已经越来越没有用武之地了。
早先的程序员说,“给我一个绘制像素的函数,我就可以绘制出整个世界。”但那个时代已经一去不复返。
DOS的硬伤在于缺乏支持。每当有新的技术问世,很少有人会在DOS中提供对这种技术的支持。无法使用新技术就意味着无法进步,但现在流行的各种操作系统则可以与时俱进。两者一比,高下立现。

我来回复

您尚未登录,请登录后再回复。点此登录或注册