主题:[原创]看了下面的对比,还有人会用 TC 来编图形程序吗?
图.为什么会这样呢? 我想原因可能在于他们认为 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,®s,®sa);
regs.h.ah=0x00;
regs.x.ax=0x4f02;
regs.x.bx=0x105;
int86(0x10,®s,®s);
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,®s,®s);
i++;
}
}
gettime(&endDraw);
getchar();
regs.h.al=regsa.h.al;
regs.h.ah=0;
int86(0x10,®s,®s);
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 高,调试工具全面,编码效率高的多!