【问题标题】:Allocation of Return Values of User Defined Functions: Performance? [duplicate]用户定义函数返回值的分配:性能? [复制]
【发布时间】:2017-05-09 17:26:28
【问题描述】:

考虑到我们可能不希望总是在多次调用中存储函数的返回值的情况,请使用以下代码:

  int foo()
     {
        return 1;
     }

从以下过程中调用。

  void main()
  {
    foo();
  }

foo 的返回值会发生什么变化?在没有找到变量地址时,编译器是否将其放在备用寄存器中 - 还是在执行下一条语句时将其擦除? 如果现在改为将返回值存储在某处:

  void main()
  {
    int retval;
    retval = foo();
  }

这两种方案的性能差异是什么?是否将 retval 存储在某处会导致堆栈管理出现任何问题?

编辑:自己的配置:工具集:V100,__cdecl (/Gd):在 VS10 中运行 Win32 编译为 C++ - 内联会起作用吗?
我们只能猜测有多少特定配置适用于给定的一组答案。一本小书可能就够了!
至于性能,int 是一个糟糕的选择,也许 floatdouble 会产生更大的影响? 这个问题与建议的副本不同,如下所示: 假设 foo 的返回地址被添加到调用帧中,一种情况是 retval 的地址放在它的下方,但是如果 retval 为 NULL 是否有额外的开销?

【问题讨论】:

  • 您的问题的答案取决于架构。许多架构总是将返回值存储在寄存器中。在您的示例中,retval 可能仅存储在寄存器中,而根本不存储在堆栈中。
  • 您的代码中没有地址。 C 和 C++ 是不同的语言。选择你实际使用的那个!
  • 虽然正确的答案取决于编译器和体系结构,但您可以期望适合寄存器的返回值将通过寄存器传递。您可以稍后在调用者代码中将其存储在堆栈中。 -O3 在这两种情况下都会优化掉你所有的代码。
  • @Ap31:C 标准中既没有要求使用寄存器,也没有要求使用堆栈。实际上存在无寄存器架构和不使用堆栈的实现。并且针对特定实现的特定优化选项是完全不相关的。
  • @Olaf 你说的当然是对的,我试图做到现实

标签: c++ c function return


【解决方案1】:

因此,这在很大程度上取决于返回的确切内容。对于像int 这样的数据类型,大多数实现会将返回值填充到寄存器中,调用函数中的优化器会将寄存器视为“脏”,否则会忽略它,除非它需要将其重新用于其他用途。基本上,根本没有性能差异。

如果你返回一个更复杂的值,包含构造函数和析构函数等,编译器将不得不调用它们,除非被调用的函数是inline,并且优化器可以确定构造函数和析构函数无效。即使它们确实有效,在某些特定情况下,编译器也允许编译器省略构造函数和析构函数对返回值的调用。支持移动构造函数的 C++11 消除了对此的一些需求。无论如何,这是在这里解决的:What are copy elision and return value optimization?

对于太大而无法放入寄存器的复杂返回值,我见过的实现让调用者在堆栈上为返回值腾出一些空间,并将指向该返回值的指针传递给被调用的函数。这意味着如果调用者可以确定析构函数没有任何效果,它将简单地忽略对它的调用并将该内存部分视为“脏”以进行优化。

【讨论】:

    【解决方案2】:

    如果你不分配它,它就会丢失。 这取决于调用约定,但通常返回值是在寄存器中传递的(%rax,例如在 SysV x86_64 中),如果您不分配它,则只会重复使用该寄存器,这显然会覆盖该值。

    在第二种情况下,它会将其放入堆栈,但优化器很可能会删除代码,因为它无用。但这取决于编译器和优化器。

    【讨论】:

    • 但是,优化器仍然会删除它,独立于它的存储位置。
    • @Olaf - 在讨论语言特性的性能时,不可避免地要讨论实现的具体细节。因此,谈论不需要优化器,甚至没有在标准中提及等等与所提出的问题无关。
    • "提及特定实现的工作方式是没有意义的" - 当您谈论性能时,您必须参考特定实现的工作方式。
    • @Omnifarious:OP 不提供有关他使用的架构的信息,也不提供编译器或其他信息。我们能做的就是推测。但是谈到实现:在通过寄存器传递结果的机器上,没有什么可以“删除”的。它只是被忽略了。这仍然与优化器无关,但即使对于具有固定模式的最简单的翻译也会这样做。
    • @Bernhard:阅读和理解整个问题应该清楚 OP 只是在疯狂猜测。最简单的方法是阅读特定实现的机器代码。
    猜你喜欢
    • 2018-10-15
    • 1970-01-01
    • 2014-02-03
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-20
    相关资源
    最近更新 更多