古老的帖子:Delphi的效率


blueski推荐 [2010-1-18]
出处:csdn
作者:不详
 

转贴一个古老的帖子回复,帖子地址:http://topic.csdn.net/t/20010110/10/57103.html

偶然来找一个文件,却发现这里关于vc++和delphi的讨论很是激烈。看了大家 
  写的一些文章,觉得有些看法正确,有些就很偏颇甚至错误(也许无知?很抱歉我 
  这样说:-)。我无意与任何人争论,更愿意把这看成是技术上的讨论。应该本着公 
  正,不带偏见的态度(这并不意味着非要平分秋色,一切应以事实为准)。我用过除 
  tp1以外的所有版本的turbo  pascal,所有版本的turbo  c/borland  c++,所有版本 
  的delphi和c++  builder;以及msc  5.0/6.0,msc/c++  7.0和visual  c++  4.2/5.0。 
  不敢说有多高的水平,至少也算有一点经验吧。下面就谈一下我的看法。     
   
  1.  编译器     
  应该说borland的编译器是最好的。因为borland有全世界最好的编译器开发组(虽     
  然anders  hejlsberg离开了)。从技术上来讲,borland领先任何竞争对手至少2~3 
  年。一般来说,borland的编译器总是能生成更小的代码并且通常(并不是在任何 
  情况下)更快的代码。     
   
  紫云英、曾登高在文章中说vc++编译的程序小,这其实是使用了动态连接的结果     
  。m$把vc++的运行库(msvcrt*.dll,  msvcp*.dll,  mfc*.dll,  你看看这些文件加 
  在一起有多大)在安装windows时就放在了system/system32目录中了。两位说 
  “协商接口”的问题,恐怕是对某些英文文章的理解错误。m$就是不愿意在windows 
  中带上其他公司的运行文件,没有技术上的原因。     
   
  其实delphi/c++  builder不论在动态连接或静态连接的情况下,生成的程序都要 
  比vc++的小。比如mdi的例子程序:在delphi/c++  builder中选new  ...  |  project     
  s  |mdi  application,在vc++中用mdi  app  wizard;生成的程序功能是非常类似的。     
   
  下面是比较结果:     
  (delphi打开优化,c++  builder使用最大速度优化,vc++  5使用最小代码优化)     
   
                              delphi  3    delphi  5    c++  builder  5    vc++  5     
  dynamic  link      21k              35k              44k                        70k     
  static    link      253k            398k            467k                      490k     
   
  凡是使用了应用类库的程序(不管是mfc,owl,vcl以及新的clx框架)都要比不使     
  用的大不少。这是因为目前的智能连接(smart  link)技术还只能针对全局变量/过 
  程,而不能用于对象结构。哪怕你只使用了某个类(或被这个类间接引用)的一个 
  属性或方法,这个类以及它所引用的所有类都全部被连接到exe中。目前所有的编 
  译器都没有解决这个问题。     
   
  (ps:  其实能生成最小代码(真编译)的高级语言编译器是turbo  pascal,不信你写 
  程序比较一下:     
  program  test;     
  begin     
      writeln('hello,  world.');     
  end.     
  生成的exe不到1.5k。而同样的c程序:     
  #include       
  main()     
  {     
      printf("hello,  world.\n");     
  }     
  最精悍的c/c++编译器生成的代码也有6k。     
  )     
   
  那么几个编译器生成的代码质量又如何呢?     
  举一个例子,比如我们在编程时经常用到的for循环语句:     
  (1)  object  pascal:     
  procedure  foo;     
  var     
      i,  j:  integer;     
  begin     
      for  i  :=  0  to  15  do  j  :=  j  +  i;     
  end;     
  (2)  c++     
  void  foo(void)     
  {     
      int  i,  j;     
      for  (i  =  0;  i  <  16;  i++)  j  =  j  +  i;     
  }     
   
  delphi  3生成的代码(打开优化):                    字节数  时钟周期     
  00424aa9  33c0                    xor  eax,eax                          1     
  00424aab  40                        inc  eax                                  1     
  00424aac  83f810                cmp  eax,0x10                        1     
  00424aaf  75fa                    jnz  -0x06                              0  (可并行)     
                                                                                  -----------------     
                                                                                  8            3     
  c++  builder  5生成的代码(最大速度优化):     
  00401535  33c0                    xor  eax,eax                          1     
  00401537  40                        inc  eax                                  1     
  00401538  83f810                cmp  eax,0x10                        1     
  0040153b  7cfa                    jl    -0x06                              0  (可并行)     
                                                                                  -----------------     
                                                                                  8            3     
   
  visual  c++  5生成的代码(最大速度优化):     
  27:          for  (i  =  0;  i  <  16;  i  ++)     
  00401205  mov              ecx,dowrd  ptr  [j]                      1     
  00401208  xor              eax,eax                                          0  (可并行)     
  28:          {     
  29:              j  =  j  +  i;     
  0040120a  add              ecx,eax                                          1     
  0040120c  inc              eax                                                  1     
  0040120d  cmp              eax,10h                                          1     
  00401210  jl                foo(0x0040120a)+0ah                  0  (可并行)     
  00401212  mov              dword  ptr  [j],ecx                      0/1  (取决于上一条指令的     
  分支预测情况)     
  30:          };     
                                                                                  -----------------     
                                                                                  16          4.2  (假定分支预测准确度     
  80%)     
   
  vc++  5的最小代码优化生成也有11个字节:     
  27:          for  (i  =  0;  i  <  16;  i  ++)     
  00401205  xor              eax,eax                                          1     
  28:          {     
  29:              j  =  j  +  i;     
  00401207  add              dword  ptr  [j],eax                      1     
  0040120a  inc              eax                                                  1     
  0040120b  cmp              eax,10h                                          1     
  0040121e  jl                foo(0x00401207)+7                      0  (可并行)     
  30:          };     
                                                                                  -----------------     
                                                                                  11          4     
   
  注:     
  (1)  delphi/c++  builder的结果是用turbo  debugger直接反汇编的,vc++  5的结 
  果是从集成环境的源级调试得到的。     
  (2)  时钟周期数以pentium处理器为例,实际上,对于没有并行执行单元的cpu 
  (比如386/486和nx586等)vc++  5生成的代码速度还要更慢一些。     
  (3)  分支预测准确度源自intel的"pentium  optimization  reference"。不过与具 
  体程序密切相关,一般来说程序中的条件转移指令越密集则分支预测准确度越低。     
   
  可以看出,delphi/c++  builder的这段程序有1~1.2个时钟周期的优势。这主要是 
  因为delphi/c++  builder的编译器比较智能,根本不编译无用的废语句。     
  (有趣的是,对于这段程序而言,vc++  5的最大速度优化反而不如最小代码优化生 
  成的代码运行速度快。)   
  不要以为1~1.2个时钟周期不算什么,整个程序的快与慢就是这样一个个时钟周期     
  积累出来的。而且就这几条指令而言相当于快25%~28.6%,是非常可观的数字。     
  我没有用vc++  6测试(我从vc++  5以后不再使用vc了,因为c++  builder  5能完全     
  兼容vc  ---  这种兼容性从c++  builder  3开始就有了,不过一开始并不完善), 
  不知道是否有改进。有人有兴趣的话请测试一下。     
   
  有兴趣的话,可以去jake's  code  efficiency  challenge(http://www.xnet.com     
  /~johnjac)看一看。那有代码运行性能挑战。目前delphi/c++  builder在6项测试中保持5项     
  领先。     
  (ps:delphi  2就曾在1996年的pc  week的性能测试中击败过vc++  4.2)     
   
  2.  语言特性     
  首先我不想评价所谓“pascal是玩具语言”这种无知的说法。某些连basic都用不 
  好的人是不可能正确评价其它语言的优劣的。至于“只配高中生使用”就更加可 
  笑了:peter  norton没上过大学,id  software的john  carmack没上过大学,你不 
  服气?!请不要嘲笑高中生,大多数程序员可能永远也达不到这些“高中生”的 
  水平。创造性工作需要的是天才,你认为天才相当于什么学位?:-)     
   
  (1)  预处理,宏以及.h文件     
  object  pascal不支持预处理,其实是不需要。无法直接编译源代码的编译器才需     
  要预处理器的支持(用于翻译/规范源程序(也包括.h之类)以利于编译)。预处理器 
  的出现是因为当初ken  thompson和dennis  ritchie要在只有256k内存的pdp-11上 
  实现c编译器难度很大,才采取的折衷办法。现代大多数c/c++产品已经把预处理器 
  包含在编译器中了。  (ps:c中采用尽可能短的关键字/运算符也是由于这个历史 
  原因)    至于macro和.h则应该说是垃圾特性,只是由于兼容性的考虑才保留下来 
  的。ansi/iso  c/c++规范中明确建议:“不要使用macro和.h,应该使用程序中的 
  常量定义和函数替代”。因为macro和.h不是c/c++的语言特性(这是真的!),没 
  有明确统一的语法定义。还会导致编译速度降低,另外由于macro在每个使用的地 
  方被展开(不是调用),大量使用macro会使生成的代码臃肿。     
   
  (2)  集合,子界类型     
  c++不支持这些object  pascal的原生类型(编译器能直接识别的)。但可以用类来 
  模拟,毕竟c++的对象结构是最复杂灵活的(ada除外)。不过性能有损失。     
   
  (3)  枚举类型     
  object  pascal不支持为每个枚举元素指定值。     
  例如c/c++中可以定义:enum  aweek  {sun  =  1,  mon,  tue  ...};     
  object  pascal中只能定义:aweek  =  (sun,  mon,  tue  ...);     
   
  (4)  数组     
  c/c++不支持object  pascal中指定下标的数组,下标只能从0开始。     
   
  (5)  结构     
  object  pascal不支持struct(在pascal中称为record)中的位域(bitfield)。bit     
  field  可以bit为单位(不需要整字节)来存储结构成员,可以减小结构的存储空 
  间。不过存取效率会有所降低。   

  (6)  字符串     
  字符串处理是object  pascal的强项之一。能够支持灵活高效的串处理。严格意义 
  上讲,c/c++不能算支持原生的字符串类型。char  *和char[]更近似于用户自定义 
  类型,因为编译器不支持字符串的内存自动分配和回收,需要用户自己调用 
  malloc()和free()。object  pascal也支持c/c++风格的字符串(称为pchar)。不过 
  string类型更加强大。从实现上来看,object  pascal的string类型使用前缀表示 
  串长度(1字节前缀的shortstring和4字节前缀的long  string,两种string自动兼 
  容,并且long  string也兼容pchar),c/c++中的char  *和char[]使用后缀chr(0) 
  表示串结束。不同的表示方法对串处理性能有很大的影响:对于大量,复杂的字 
  符串操作,用object  pascal可以写出比c/c++快几十倍的程序(许多用pascal写的 
  pascal编译器,比如free  pascal,pascal  pro等,虽然技术水平一般,但编译速 
  度也很快,在某种程度上也得益于  pascal的字符串处理效率)。比如取串长度函 
  数length/strlen(),object  pascal的实现只需要一条mov指令,而c/c++的实现 
  则需要进行重复串扫描直到找到结尾0为止。object  pascal的string类型在支持 
  unicode字符方面也有优势。要知道c/c++的字符串给现代操作系统支持unicode字 
  符带来了很大的困扰,比如串'abc'的unicode表示为:41  00  42  00  43  00,这使 
  c/c++程序根本无法处理这种字符串。虽然修改编译器可以很容易解决这个问题, 
  但光修改编译器是不够的,还要修改操作系统,否则以前的大量c/c++程序根本无 
  法在新操作系统上使用(这简直是灾难  ---  你连notepad都没了,怎么办?:-)。 
  windows采用凡是涉及字符串处理的api都提供两套的解决方案。比如textout, 
  有用于处理ascii字符的textouta和用于处理unicode字符的textoutw。而 
  unix/linux采用另一种办法:凡是涉及字符串处理的api都使用utf8压缩编码(一种 
  类似于rtf的编码方法:凡是ascii字符都直接存储,多字节字符则用\进行转义), 
  虽然(勉强)保证了兼容性却也代价不小。     
  (ps:c++中的string/ansistring是用类模拟的,所以性能...)     
   
  (7)  多重继承     
  毫无疑问,object  pascal不支持多重继承;并且也看不出borland有增加这一特     
  性的意向(其实增加是轻而易举的)。object  pascal通过接口(interface)实现多 
  重继承.interface不仅可以引入用object  pascal实现的对象,也可以引入其他 
  语言实现的com/dcom/corba对象。你真的需要多重继承吗?我想大多数程序员和 
  我一样都从来没有使用过多重继承(连vcl这么强大灵活的体系结构都根本没有用 
  到多重继承)。(ps:java和delphi一样不支持多重继承,也使用interface来实 
  现多重继承。其实这并不奇怪:jdk  1.2和java  2主要是由borland开发的,sun 
  只挂名而已。不信你看java类库是不是和vcl很象。:-)     
   
  (8)  对象模板     
  object  pascal不支持对象模板。因为对象模板不过是宏的语言实现而已(宏本身     
  不是c/c++的语言特性)。     
   
  (9)  重载     
  object  pascal支持函数/过程的重载,不支持运算符重载。c++全部支持。     
  (ps:我个人倾向于object  pascal应该增加对运算符重载的支持)     
   
  (10)  位及逻辑操作     
  object  pascal和c/c++在这方面没什么差别。c/c++的&,|,~,^,>>, < <,&&, 
  ||,!等效于object  pascal的and,or,not,xor,shr,shl(and,or,not,xor 
  既用于位操作也用于逻辑操作)。不过c/c++不支持逻辑xor(a  xor  b  =  a  and  not 
    b  or  not  a  and  b,还是可以实现的)。     
   
  (11)  风格     
  其实这是我更倾向于使用delphi的一个重要原因(由于工作的原因,我也经常使 
  用c++和汇编)。就象有些文章所说的:“object  pascal和c++是同一重量级的语 
  言”,确实难分轩轾,差别反而主要是在风格上。c++强调灵活,而object  pascal 
  更注重整洁和优美。《程序设计语言:设计与实现》一书的作者也称赞pascal是 
  “一种极优美的语言”。有人因此认为pascal“笨拙”。其实应该是“大道至简” 
  。我认为即使用c++写程序也还是工工整整的好,不要卖弄技巧。只有水平不高 
  不低的程序员才喜欢卖弄技巧(水平太低的卖弄不了,太高的又不愿卖弄了)。就 
  象有人评李昌镐的棋“平淡”,但马晓春再怎么“鬼才”也只能甘拜下风。     
   
  上面说的其实都是c++  vs  object  pascal。不过也适用于vc++  vs  delphi。     
  (ps:vc++其实并未实现全部ansi/iso  c++  95规范(目前的最新标准)的特性 
  (所以有人戏称之为c+)。而c++  builder则完全兼容ansi/iso  c++  95规范,并支 
  持at&t(c的诞生地)和unix  v的全部c++扩展特性。有人称“m$坚持工业标准, 
  borland随意修改”,这是不对的。delphi也全兼容ansi/iso  pascal  1983/92规 
  范,以及apple  object  pascal  (用过code  warrior  professional的应该知道 
  apple的object  pascal)。)     
   
  3.  功能及其他     
  (1)  易用性     
  毫无疑问delphi有巨大优势,这不用多说了吧。     
  (ps:delphi的真正伟大之处在于并不因为易用而降低技术水准。你需要复杂性 
  就有复杂性,你需要灵活性就有灵活性;不用可视化也一样写程序(可视化只是 
  object  pascal  对象结构的另一面),不用vcl也一样写程序)     
   
  (2)  适用范围     
  vc++几乎能做任何硬件允许的工作。delphi也能。(“不!!!”,我知道你会 
  这样说,你会举出vxd。:-)  delphi不能写vxd(其实如果你用delphi生成obj, 
  再用m$的link连接,是可以的)是有原因的(你见过非m$的工具能生成vxd的吗? 
  watcom?symantec?gnu?...),但不是技术上的原因。vxd的le(linear  executable) 
  文件格式最早出现在windows  3.0中,格式很简单(比ne和pe格式都要简单), 
  基本上是内存映象文件。但m$不知道出于什么动机就是不允许其他公司的软件生 
  成它的这种(专利)格式。delphi是可以写windows  nt的sys和新的wdm(windows   
  driver  model)驱动程序的,这些使用普通的dll格式。     
  (ps:从法律角度讲,你自己写一个程序,未经m$允许生成ms  word文件也是不行     
  的)     
  (ps:玩过“奇迹时代”(age  of  wonders,http://www.epicgames.com)吗?是用     
   
  delphi  3写的。画面和速度都优于m$的“帝国时代”。不过我不喜欢玩策略类游     
  戏,我喜欢的是duke3d和quake系列,还有tomb  raider系列。:-)     
   
  (3)  集成开发环境     
  delphi的ide更简洁/好用一些。     
   
  (4)  数据库支持     
  在这方面除了delphi的兄弟c++  builder/jbuilder恐怕只有power  builder能(勉     
  强)与delphi相比。不过pb的性能和使用范围就差得太远了(要不怎么叫poor  builder呢     
  ?:-)。     
  (ps:我的印象是现在大多数基于网络/大型数据库的c/s和多层结构的应用都是用     
   
  delphi/jbuilder开发的)     
   
  (5)  网络功能     
  delphi也有一定的优势。尤其是在internet开发方面。     
   
  (6)  组件支持     
  delphi除了基于object  pascal的vcl/clx外,也支持基于com/dcom的组件(比如 
  activex),另加corba支持。vc++只支持支持基于com/dcom的组件。     
   
  (7)  应用框架/设计思想     
  vcl比mfc至少领先一代,这也毋须多言。mfc充其量不过是对owl的(一种不太成功     
  的)模仿而已,从设计思想上看甚至还不如owl。作为一种语言的基本类库(不论可 
  视与否),应该从大处着眼,力求简洁有效,保持一定的弹性和抽象度(抽象意味 
  着从功能出发,比如vcl中的tcanvas就是对windows中dc(device  context)的一种 
  极好的抽象,比起mfc中的设计高明了何止一点半点)。而不是面面俱到,一一照 
  搬apis(不幸的是,m$的程序员多年以来一直在不辞劳苦地做这项工作)。看看mfc 
  的某些类,简直惨不忍睹:通常除了省了hwnd和dc之类的参数(已经作为类的私有 
  数据保存了),其方法(method)简直就是windows  api的翻版。这样做有什么意义 
  呢?windows  api不就摆在那里吗?比如说,使用mfc中的线程类还不如直接调用 
  createthread/exitthread/resumethread/setthreadpriority之类的api更方便快 
  速呢。     
  (ps:用过delphix(http://www.yks.ne.jp/~hori/)吗?directx这么繁杂的结构     
  可以用object  pascal封装得如此之好再次证明了vcl体系结构的强大)     
   
  (8)  调试     
  两者相差无几。vc++的源级调试更用户友好一些,而delphi/c++  builder对多线     
  程程序的调试支持更好。     
  (ps:要比单独的调试工具,borland的turbo  debugger可就要比m$的codeview强     
  多了)     
   
  (9)  运行环境/系统需求     
  应该说差不多。vc++的启动速度确实要快于delphi(这主要是相对于delphi  4+而     
  言,delphi  3的启动还是很快的)。这很大程度上是由于一个事实:vc++主要是 
  一个基于文本编辑器的传统开发环境。code  warrior  professional不是启动更快 
  吗?至于“一个数据库程序要带上3~5mb的bde运行文件”的说法,这可能是由于 
  在安装制作工具(installsheild,wise之类)中使用了“全部bde安装”(默认)而 
  不是“部分bde安装”。如果你只使用access,dbase,foxpro,paradox之类的桌 
  面数据库,只需要几百k的运行文件就可以了。用m$的工具开发的数据库程序也要 
  带上一大堆odbc,dao,jet,ado,msde之类的运行文件。在delphi  5中,如果 
  使用adoexpress,interbase  express访问数据库的话,可以不带bde。     
  (ps:不管怎么说,borland在delphi/c++  builder的启动速度方面还是要努力改     
  进!)     
  (10)  产品质量/稳定性     
  有文章称“vc++的质量好,稳定性高”。真的是这样吗?visual  studio的servi     
  ce  pack不是都出到4了吗?什么是service  pack?主要不就是bug  fix  +  patch吗?! 
  borland的工具也并不完美,delphi  3的vcl中确实存在“内存漏洞”,会导致用 
  d3开发的程序有时(并不总是)退出后不能释放分配的内存。vc++的问题也不少: 
  ie是用vc++写的吧,上网时多启动几个,开开关关,最后全关闭,看看你的系统 
  资源剩下多少了?还经常导致“general  protection  error”。ultra  edit是用 
  vc++写的吧,也有同样的问题。其实说到底,程序质量好不好,运行稳定不稳定, 
  主要取决于开发者的水平/责任心。比如说tomb  raider系列和quake系列游戏同 
  是用vc++开发的,但画面质量和运行速度显然quake系列更胜一筹。象美国航空 
  航天局(nasa),俄罗斯宇航局(rsa),美洲银行(bankof  america,资产超过5000亿 
  美元的大银行),其他诸如american  airlines,at&t,bmw,compaq,bbc  television, 
  british  telecom等大型机构/公司都在用delphi开发复杂的,企业级(可笑的是, 
  有人居然称“用vc开发企业级的桌面应用”,殊不知企业级应用和桌面应用是相 
  对而言的)的应用系统(在http://community.borland.com(borland社团站点)上 
  有关于用delphi和c++  builder开发的产品介绍),如果有人还要说“...稳定和 
  可靠是硬道理,只好忍痛割爱了”,那他恐怕只好自制开发工具 
   
  (ps:关于delphi与某些显卡驱动冲突的问题,是由于某些显卡(如s3  virge  gx)     
  的老版本驱动程序不能正确处理windows公用控制中的imagelist的绘制方法造成 
  的,在这种情况下所有在imagelist中使用多个图象的程序都会有问题)     
  (ps:至于“一看到很多优秀的共享软件冒出具有delphi特色的错误异常就感到 
  悲  哀”,建议此人先搞清楚你看到的“错误异常”消息是这些软件本身出错呢, 
  还是运行时的异常处理消息(比如“没有找到指定文件”或“索引超出范围”之 
  类)再说。delphi中有完善的异常处理,所以很多程序员不再写错误处理,而放 
  手让编译器去处理。我认为这不是一个好习惯,至少弹出的消息对话框可能与 
  你的程序所用的语言/风格不一致。让人家误会了不是?:-)