【问题标题】:Are goto statements efficient when compared to calling functions? [closed]与调用函数相比,goto 语句是否有效? [关闭]
【发布时间】:2012-12-20 20:20:05
【问题描述】:

我在这里有以下 C++ 代码:

#include <iostream>

int main(int argc, const char * argv[])
{
    goto line2;
line1:
    std::cout << "line 1";
    goto line3;
line2:
    std::cout << "line 2";
    goto line1;
line3:
    std::cout << "line 3";
    goto line4;
line4:
    std::cout << "Hello, World!\n";
    return 0;
}

如果我制作了一个更大的程序,比如说 10,000 行代码,并且我决定永远不会使用我自己编写的函数,我只会使用 goto 语句。我只使用全局变量。我在最佳实践方面有点疯狂,但它有一个非常具体的目的。问题是,使用 goto 语句跳转是否有效?如果我有 1000 个 goto 标签怎么办?

goto 语句是否直接转换为机器代码,告诉计算机只是跳转到不同的内存地址?与调用函数的成本相比,这样在机器中跳转的成本是否更低?

我想知道,因为我想编写一个非常高效的程序来进行一些计算,并且我需要非常高效,而无需求助于汇编/机器代码。


无需告诉我,就维护、代码的可理解性、最佳实践而言,这是一个坏主意,我非常清楚这一点,我只是希望得到这个问题的答案。我不想在函数调用好用还是 goto 好用之间争论。


为了澄清这个问题,在这种仅将 goto 用于 10,000 行程序的情况下,我担心它与使用函数的传统程序相比如何。有多种方法可以比较和对比这两个程序,例如 CPU 缓存将如何执行。如果没有函数调用,它将提供什么样的节省。如果没有调用堆栈,这将如何影响 CPU 缓存,因为 CPU 缓存通常会保持堆栈关闭。因此,是否会出现由于未正确使用缓存而导致性能下降的情况。与时间效率方面的跳跃相比,调用函数的实际成本是多少。有很多方法可以在效率方面比较和对比两种编程风格。

【问题讨论】:

  • 请不要这样写代码。永远。
  • 为什么每个人都觉得有必要告诉我这个?...我已经在商业上编写代码超过 15 年,并在 12 岁时开始编程,我从来没有写过这样的代码。除了在这种特殊情况下,对于我自己的项目。
  • 有趣的是,每个看到这个问题的人都会立即想到“哦,不,gotos,那是邪恶的”,但您没有考虑到这样做有一些充分的理由。我正在开发一种编译为 C++ 代码的计算机语言,并且需要使用 Goto 语句将执行转移到语言的不同部分。你知道 C++ 用于编译成 C 代码然后由 C 编译器编译吗? Coffeescript 编译为 Javascript 并作为 Javascript 执行。如果我在代码中使用跳转到许多不同位置,我正在开发的语言更容易编译为 C++。
  • 请记住,计算机只是一台执行指令的机器,我们如何使用它取决于我们。
  • 我不是说“gotos 那是邪恶的”我是说“gotos 而不是函数调用,那是邪恶的”我编写了使用 gotos 的代码,你不能真正将 C++ 编译为 C使用当前版本的语言,至少效率不高。你打算写的正是促使“Goto被认为是有害的”论文的那种东西。

标签: c++ c assembly goto machine-code


【解决方案1】:

goto 语句是否直接转换成机器码,告诉计算机只是跳转到不同的内存地址?

是的。

与调用函数的成本相比,这样在机器中跳转的成本是否更低?

是的。

但是,当编译器看到函数调用时,它不必实际生成代码来调用函数。它可以利用函数的核心并将它们固定在调用所在的位置,甚至不会跳转。所以调用函数会更有效率!

此外,您的代码越小,效率就越高(一般来说),因为它更可能适合 CPU 缓存。编译器可以看到这一点,并且可以确定函数何时较小最好内联,或者何时较大最好将其分离并使其成为真正的函数,以生成最快的代码(如果您将其设置为生成最快的代码)。您看不到这一点,因此您猜测并且可能猜错了。

这些只是一些显而易见的。编译器可以做很多其他的优化。让编译器决定。它比你聪明。它比我聪明。 编译器无所不知。说真的,Cthulhu 可能是一个编译器。

你说过不要,但我要说:我强烈建议你在决定这样做之前配置你的代码,我几乎可以保证这不值得你花时间。编译器(其中大多数是接近 AI 级别的智能)可能可以通过常规函数调用生成同样快或更快的代码,更不用说维护方面了。

【讨论】:

  • 优化不仅仅是避免函数调用重载。很好,你提到了 CPU 缓存的事情。
  • @Krishnabhadra 是的,我并不是说这是编译器所能做的。我会记下来的。
  • 我非常不喜欢回答说“编译器比你更聪明”的优化问题。现在可能是真的,但让它成为假并不需要太多。在很大程度上,编译器远非智能。它们只是快速而持久。关于代码大小的第二段也具有误导性;相对于具有高级代码知识的合格程序员而言,编译器实际上处于严重劣势。但是,尽管我不同意大部分答案,但内联主要针对函数执行的基本观点是正确的。
【解决方案2】:

1) 问题是,使用 goto 语句跳转是否有效?如果我有 1000 个 goto 标签怎么办?

从您的带有 4 个goto 标签的小示例中,您来回跳转,不,它在性能方面效率不高。为了避免函数调用机制的开销,此方法禁用了编译器会自动为您执行的许多其他优化。我没有列出它们,但this 值得一读。

2) goto 语句是否直接转换成机器码,告诉计算机跳转到不同的内存地址?

是的(正如其他人正确指出的那样)

3) 与调用函数的成本相比,这样在机器中跳转的成本是否更低?

是的,只有当你的编译器是历史前的,并且没有内置任何优化机制时。否则否。

我不是在谈论最佳实践..

【讨论】:

  • 请考虑 10,000 行代码中的 1000 个 goto 语句。
  • @Phil 再次(正如他在评论中指出的那样),没有人可以回答这个问题 1)没有看到你的 10,000 行代码(但我不想看到它)2)了解编译器/machine 你运行这个 3)你正在启用/禁用的编译器优化.. 我们只能这样说 - 在正常情况下,使用现代编译器,程序员不必担心函数调用机制的开销。同样,这取决于编译器。
【解决方案3】:

很难准确回答您的查询,这取决于您的程序的复杂性和其中使用的 goto 语句。

goto 语句等价于无条件跳转指令(例如 jmp )。 goto 的范围将在文件内。

Ritchie 建议避免使用 goto 语句,如果仍想/必须使用 goto 语句,则使用自顶向下的方法,不要使用自底向上的方法。

这些是教科书的详细信息。

实际上,您应该非常确定在哪里使用 goto 语句以及在 goto 跳转后您的程序流将在哪里,否则正如您提到的 1000 条 goto 语句,您也很难决定程序流,忘记其他。因此,进一步改进您的程序将非常非常困难。

还有很多其他工具,例如循环、条件语句、break 和 continue 语句、函数等,可以帮助您避免此类问题。

希望对你有帮助.....

【讨论】:

  • 查询 ----> goto 语句是否直接转换为机器代码,告诉计算机只是跳转到不同的内存地址? repy ----> goto 语句等同于无条件跳转指令(例如 jmp )。 goto 的范围将在文件内。
  • 查询 ------> 问题是,使用 goto 语句跳转是否有效?如果我有 1000 个 goto 标签怎么办?答案-------> 实际上,您应该非常确定在哪里使用 goto 语句以及在 goto 跳转后您的程序流程将在哪里,否则正如您提到的 1000 个 goto 语句,您也很难决定程序流程,忘记别人。因此,进一步改进您的程序将非常困难。
【解决方案4】:

简而言之,'GoTo' 语句可能很有效,但这就是它们的实际使用方式。根据 Herbert Schildt(C++ from the GROUND UP)的说法,“没有需要使用 goto 语句的编程情况——它不是使语言完整的必要项。”归根结底,许多程序员不喜欢该语句的主要原因是 goto 语句往往会使您的代码混乱和/或使其非常难以阅读,因为根据名称,goto 可以从一个地方跳到另一个地方。话虽如此,有时 goto 语句可以减少混乱并提高代码效率,但这完全取决于您如何使用它们以及使用它们的上下文。就个人而言,我建议使用函数调用,与几个 goto 语句相反;其他人可能不同意。

【讨论】:

  • 谢谢,礼貌-我知道这一点。我不想在 goto 和函数调用之间展开辩论。
  • 大声笑,是的,我看到你的最后一行有点晚了,我很抱歉。
【解决方案5】:

是的,从 goto 生成的机器代码将是一个直接的 JUMP。这可能会比函数调用更快,因为不需要对堆栈做任何事情(尽管没有任何要传递的变量的调用将被优化为可能同样快)。

当这段代码出现问题时,上帝会帮助你。或者当其他人必须维护它时。

【讨论】:

  • 或者当其他人必须维护它时..哎哟..
  • 这是一个严重的过度简化。编译器执行称为优化的事情。我敢打赌,编译器会在使用函数时生成更优化的代码,而不是包含 1000 个 goto 的 10,000 行代码。
  • 如果你再看一遍我所说的,你会发现我试图小心不要过度简化优化器将实现或不会实现的目标。
  • @krishnabhadra。一旦这成为一段不平凡的代码,它可能会比函数调用快一点。一段不平凡的代码将包含足够多的变量,编译器不会优化掉或内联所有函数调用。结果,堆栈将偶尔被压入或弹出。这不会更快。并不意味着 goto 更好。事实上恰恰相反。
  • +1 有很多评论的人似乎对代码优化或编译器如何处理 goto 一无所知。
【解决方案6】:

goto 语句是否直接翻译成机器码 告诉计算机只是跳转到不同的内存地址?

差不多。

当机器像这样跳来跳去时,这是不是成本更低? 与调用函数的成本相比?

函数调用将进行非常相似的跳转,但在跳转之前,您必须为新函数设置新的堆栈框架,根据调用约定推送参数,并在结束时设置提高任何返回值并展开。是的,不这样做可能会更快。

我有点疯了

是的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-12
    • 1970-01-01
    相关资源
    最近更新 更多