关于最优无限循环的考证

   昨天在一个论坛里看到一个帖子,是关于无限循环的选择问题,之前也看到过很多次说空for比while(1)效率高的论述,只是之前一直没有功夫去考证。
   话不多说,直入正题。
/*
 *\brief 示例一:空for  
 
*/ 
int main() 
{    
  for(;;)    
  {}  
  return 0; 
}

/* 
 *\brief 示例二:while(1)  
 
*/ 
int main() 
{     
  while(1) 
  {}     
  return 0; 
}
   借用曾经看到的某论坛大师逢帖必发的一句话“不要迷信语言,要迷信编译器”,撇去我对此人的偏见,对于这句话我还是比较认同的,毕竟自己写的代码最终是由你用的编译器来编译并连接成的,语言只是你和它打交道的中介,至于最终怎么解释执行,完全是它有最终解释权。
   有点偏题,直接上编译器生成的汇编码(注,此处编译器及版本为:g++ (GCC) 4.4.6 20120305)
400554:   55                      push   %rbp   
400555:   48 89 e5              mov   %rsp,%rbp   
400558:   eb fe                  jmp    400558 <main+0x4>   
40055a:   90                      nop    
40055b:   90                      nop    
40055c:   90                      nop    
40055d:   90                      nop    
40055e:   90                      nop    
40055f:   90                      nop
   两者生成的汇编代码一致,就不多贴一份了。
   事实证明,两种无限循环写法最终运行效率一样,但是为什么这么多人说空for要比while(1)效率高呢?这其中还不乏一些很大的知名开源团队。出于科学求证的态度我又测试了老的GCC版本(g++ (GCC) 3.2.4),证明和上面大体是一样的。但是当我用VS2010和VC6.0测试时区别就出来了。
   结果如下:
for(;;) 的反汇编:  
int main()
{
00411350  push        ebp  
00411351  mov         ebp,esp  
00411353  sub         esp,0C0h  
00411359  push        ebx  
0041135A  push        esi  
0041135B  push        edi  
0041135C  lea         edi,[ebp-0C0h]  
00411362  mov         ecx,30h  
00411367  mov         eax,0CCCCCCCCh  
0041136C  rep stos    dword ptr es:[edi]  
    for(;;)
    {
    }
0041136E  jmp         main+1Eh (41136Eh)  
    return 0;
00411370  xor         eax,eax  
}

while(1)的反汇编: 
int main() 

00411350  push        ebp   
00411351  mov         ebp,esp   
00411353  sub         esp,0C0h   
00411359  push        ebx   
0041135A  push        esi   
0041135B  push        edi   
0041135C  lea         edi,[ebp-0C0h]   
00411362  mov         ecx,30h   
00411367  mov         eax,0CCCCCCCCh   
0041136C  rep stos    dword ptr es:[edi]       
   while(1) 
0041136E  mov         eax,1   
00411373  test        eax,eax   
00411375  je          main+29h (411379h)       
   {     
   } 
00411377  jmp         main+1Eh (41136Eh)       
   return 0; 
00411379  xor         eax,eax  
 }
   显而易见,VS平台下for(;;)生成的汇编指令少,并且不占用寄存器,没有多余的判断和跳转,比while (1)性能要好。
   其实这种平台相关的代码之前我也在一篇博文中说过(见:编译器背后的小故事),
   C++标准仅仅是一些规则,而编译器才是最终规则的实现者,对于很多细节规则并没有限定,这也要求我们尽量明确写出与编译器实现差异无关的代码,就如char的实现是按照signed还是unsigned等等,这些标准没有具体说明,各个编译器厂商自然会有各自的实现方法,很多时候我们在一个平台习惯的东西,换到另一个平台就不一定凑效,这时候就需要我们知道编译器具体实现的过程,或者只需要看一下实现的结果。
   正如那句“不存在没有bug的程序,只存在暂时未发现bug的程序”一样,程序员的世界里,“没有最好,只有更好” 也是至理名言       ---peakflys

posted on 2013-01-05 12:39 peakflys 阅读(3132) 评论(8)  编辑 收藏 引用 所属分类: C++

评论

# re: 关于最优无限循环的考证 2013-01-05 16:40 Lo

比较得不对 用的是调试版,看看发布版的代码,会直接优化得没了  回复  更多评论   

# re: 关于最优无限循环的考证 2013-01-05 17:05 peakflys

上面的汇编代码是建立在GCC编译未加-O优化,VS用的也是debug版本,目的是为了说明 所谓广为流传的for(;;)比while(1)效率更好的说法是编译器相关的,当然GCC和VS下编程同意网上说的无限循环优先选用for(;;),至于VS的release版本,还有其他编译器平台,有兴趣的可以自己去验证一下。@Lo
  回复  更多评论   

# re: 关于最优无限循环的考证 2013-01-05 19:38 Lo

发布版会是一样的  回复  更多评论   

# re: 关于最优无限循环的考证 2013-01-06 11:01 zgpxgame

由于现在的CPU指令流水线、缓存、乱序等等,加上编译器会处理优化,所以这方面的优化已经意义不大了,也就不必纠结用什么循环了。不过了解一下也是可以的  回复  更多评论   

# re: 关于最优无限循环的考证 2013-01-06 14:07 peakflys

在硬件性能和编译器优化能力不断提升的今天,程序员的门槛一降再降,甚至出现了半月培训即可入岗的事情,但是如果想要写出优质高效的代码,就一定要熟悉你所使用的编译器,不能完全寄望于编译器的优化,养成良好的书写习惯才是王道。@zgpxgame
  回复  更多评论   

# re: 关于最优无限循环的考证 2013-01-06 18:31 zgpxgame

恩 很欣赏你的这种做法。只是我觉得你分析得不够全面,所以就补充了我自己的一点看法。所以我认为考证后的结论是,不需要纠结于for还是while。与之相比,干净的代码和能清晰表达程序意图的语句往往是更重要一些的  回复  更多评论   

# re: 关于最优无限循环的考证 2013-01-08 19:26

for(;;)比while(1)编写效率高(少一个字节……)  回复  更多评论   

# re: 关于最优无限循环的考证 2013-01-09 13:15 peakflys

恩?@花
  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2024年3月>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

导航

统计

公告

人不淡定的时候,就爱表现出来,敲代码如此,偶尔的灵感亦如此……

常用链接

留言簿(4)

随笔分类

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜