C / C ++:GOTO比WHILE和FOR更快吗?

我知道,每个人都讨厌GOTO,没有人推荐它。 但那不是重点。 我只想知道,哪个代码最快:

  1. goto循环

     int i=3; loop: printf("something"); if(--i) goto loop; 
  2. while循环

     int i=3; while(i--) { printf("something"); } 
  3. for循环

     for(int i=3; i; i--) { printf("something"); } 

一般来说, forwhile循环被编译为与goto相同的东西,所以它通常不会有所作为。 如果你有疑虑,你可以随意尝试这三个,看看哪个需要更长的时间。 即使你循环十亿次,你也无法衡量差异。

如果你看一下这个答案 ,你会发现编译器可以为forwhilegoto生成完全相同的代码(仅在这种情况下没有条件)。

写短程序,然后执行以下操作:

 gcc -S -O2 p1.c gcc -S -O2 p2.c gcc -S -O2 p3.c 

分析输出,看看是否有任何差异。 一定要引入一定程度的不可预测性,以便编译器不会将程序优化为零。

编译器在优化这些微不足道的问题方面做得很好。 我建议不要担心它,而是专注于让你作为程序员更有效率的东西。

速度和效率是一个值得担心的好事,但99%的时间都涉及使用正确的数据结构和算法…而不用担心一个for是否比一段while还是一个goto更快等等。

我唯一一次见到goto的论点是在W. Richard Stevens的一篇文章或书中。 他的观点是,在一个非常时间关键的代码部分(我相信他的例子是网络堆栈),嵌套的if / else块以及相关的error handling代码可以使用goto以一种有价值的方式重做。

就个人而言,我对程序员与史蒂文斯的工作争论并不够好,所以我不会尝试。 goto对于与性能相关的问题很有用,但是时间的限制是相当严格的。

它可能是编译器,优化器和架构特定的。

例如代码if(--i) goto loop;条件测试,后跟无条件分支 。 编译器可能只是生成相应的代码,或者它可能足够智能(尽管编译器至少没有那么多智能可能不值得),以生成单个条件分支指令。 while(i--)另一方面while(i--)已经是源级别的条件分支,因此无论编译器实现或优化器的复杂程度如何,在机器级别转换到条件分支可能更有可能。

最后,差异可能是微小的,只有在需要大量迭代时才有意义,你应该回答这个问题的方法是为感兴趣的特定目标和编译器(和编译器设置)构建代码,以及检查生成的机器级代码或直接测量执行时间。

在你的例子中,循环中的printf()在任何情况下都会占据任何时间; 循环中更简单的东西会更容易观察差异。 我建议一个空循环,然后声明i volatile以防止循环被优化为空。

只要您生成与普通循环相同的控制流,几乎任何体面的编译器都能生成相同的代码,无论您是否使用forwhile等。

你可以通过使用goto获得一些东西,但通常只有当你正在生成一个普通循环根本不能(至少干净)的控制流时。 一个典型的例子是跳到循环的中间以获得一个循环和一个半结构,大多数语言的正常循环语句(包括C)都不能干净地提供。

所有循环和goto之间不应该有任何显着差异。 除了这个想法,该编译器更可能不会尝试优化GOTO事物。

尝试在循环中优化编译器生成的东西并没有多大意义。 优化循环内的代码或减少迭代次数等更有意义。

我认为在nornal条件下编译后会有一些代码。

事实上,我觉得goto有时很方便,虽然很难阅读。

有几个利基垂直,其中goto仍然常用作标准练习,由一些非常非常聪明的人在这些设置中没有偏向goto。 我曾经在一家以模拟为重点的公司工作,在那里所有当地的fortran代码都有很多东西,团队非常聪明,而且软件工作接近完美。

因此,我们可以将goto的优点放在一边,如果问题仅仅是比较循环,那么我们通过分析和/或比较汇编代码来实现。 但是,这个问题包括像printf等的语句。在这样做时,你无法真正讨论循环控制逻辑优化。 此外,正如其他人所指出的那样,给定的循环都将生成非常类似的机器代码。

除了通常将小循环扩展为无循环之外,所有条件分支在流水线处理器体系结构中被认为是“采用”(真实),直到解码阶段。 因此,根据Harper的观点,goto在简单的循环控制中具有任何优势是不现实的(正如同时或彼此没有优势一样)。 当将goto检查的附加条件添加到嵌套循环的EACH或嵌套ifs是次优的时候,GOTO通常在多个嵌套循环或多个嵌套ifs中有意义。

在简单循环中优化搜索类型的操作时,使用sentinal有时比其他任何方法更有效。 本质上,通过在数组的末尾添加一个虚拟值,您可以避免检查两个条件(数组的结尾和找到的值)只是一个条件(找到的值),并在内部保存cmp操作。 我不知道编译器是否会自动执行此操作。