Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
其中,如果有,C++;编译器是否进行尾部递归优化? 在我看来,在C和C++中做尾递归优化都是很好的,然而在调试的时候,我似乎从来没有看到一个表示这个优化的帧堆栈。这有点好,因为堆栈告诉我递归有多深。不过,优化也会很好 是否有任何C++编译器进行了这种优化?为什么?为什么不呢_C++_Optimization_Tail Recursion - Fatal编程技术网

其中,如果有,C++;编译器是否进行尾部递归优化? 在我看来,在C和C++中做尾递归优化都是很好的,然而在调试的时候,我似乎从来没有看到一个表示这个优化的帧堆栈。这有点好,因为堆栈告诉我递归有多深。不过,优化也会很好 是否有任何C++编译器进行了这种优化?为什么?为什么不呢

其中,如果有,C++;编译器是否进行尾部递归优化? 在我看来,在C和C++中做尾递归优化都是很好的,然而在调试的时候,我似乎从来没有看到一个表示这个优化的帧堆栈。这有点好,因为堆栈告诉我递归有多深。不过,优化也会很好 是否有任何C++编译器进行了这种优化?为什么?为什么不呢,c++,optimization,tail-recursion,C++,Optimization,Tail Recursion,我该如何告诉编译器去做呢 对于MSVC:/O2或/Ox 对于GCC:-O2或-O3 检查编译器是否在特定情况下执行了此操作,如何 对于MSVC,启用PDB输出以能够跟踪代码,然后检查代码 对于GCC 对于如何确定编译器是否对某个函数进行了这样的优化,我仍然会接受一些建议(尽管康拉德让我假设它,这让我感到放心) 通过执行无限递归并检查是否会导致无限循环或堆栈溢出(我使用GCC执行此操作并发现-O2足够了),始终可以检查编译器是否执行此操作,但我希望能够检查我知道将终止的某个函数。我希望有一

我该如何告诉编译器去做呢

  • 对于MSVC:
    /O2
    /Ox
  • 对于GCC:
    -O2
    -O3
检查编译器是否在特定情况下执行了此操作,如何

  • 对于MSVC,启用PDB输出以能够跟踪代码,然后检查代码
  • 对于GCC
对于如何确定编译器是否对某个函数进行了这样的优化,我仍然会接受一些建议(尽管康拉德让我假设它,这让我感到放心)

通过执行无限递归并检查是否会导致无限循环或堆栈溢出(我使用GCC执行此操作并发现
-O2
足够了),始终可以检查编译器是否执行此操作,但我希望能够检查我知道将终止的某个函数。我希望有一个简单的方法来检查这个:)


经过一些测试,我发现析构函数破坏了进行这种优化的可能性。有时,更改某些变量和临时变量的范围以确保它们在return语句开始之前超出范围是值得的


如果在尾部调用后需要运行任何析构函数,则无法进行尾部调用优化。

所有当前主流编译器都能很好地执行尾部调用优化(并且已经进行了十多年),例如:

让编译器进行优化很简单:只需打开速度优化:

  • 对于MSVC,使用
    /O2
    /Ox
  • 对于GCC、Clang和ICC,使用
    -O3
检查编译器是否进行了优化的一个简单方法是执行一个调用,否则会导致堆栈溢出,或者查看程序集输出


作为一个有趣的历史记录,Mark Probst在一次测试过程中将C的尾部调用优化添加到GCC中。本文描述了实现中一些有趣的注意事项。这本书值得一读。

大多数编译器在调试版本中不进行任何类型的优化


如果使用VC,请尝试打开PDB信息的发布版本-这将让您跟踪优化后的应用程序,您应该希望看到您想要什么。然而,请注意,调试和跟踪优化的构建将使您四处奔波,并且通常您无法直接检查变量,因为它们只会在寄存器中结束或完全优化。这是一种“有趣”的体验…

正如格雷格所提到的,编译器不会在调试模式下进行。调试构建比prod构建慢是可以的,但它们不应该更频繁地崩溃:如果您依赖于尾部调用优化,它们可能会做到这一点。因此,通常最好将尾部调用重写为普通循环:-(

GCC4.3.2将此函数(蹩脚/琐碎的
atoi()
实现)完全内联到
main()
中。优化级别是
-O1
。我注意到如果我使用它(即使将其从
静态
更改为
外部
,尾部递归也会很快消失,因此我不会依赖它来保证程序的正确性

#include <stdio.h>
static int atoi(const char *str, int n)
{
    if (str == 0 || *str == 0)
        return n;
    return atoi(str+1, n*10 + *str-'0');
}
int main(int argc, char **argv)
{
    for (int i = 1; i != argc; ++i)
        printf("%s -> %d\n", argv[i], atoi(argv[i], 0));
    return 0;
}
#包括
静态整数原子(常量字符*str,整数n)
{
如果(str==0 | |*str==0)
返回n;
返回原子(str+1,n*10+*str-'0');
}
int main(int argc,字符**argv)
{
对于(int i=1;i!=argc;++i)
printf(“%s->%d\n”,argv[i],atoi(argv[i],0));
返回0;
}
除了显而易见的(除非您要求,否则编译器不会进行此类优化)之外,C++中的尾部调用优化也很复杂:析构函数

假设:

   int fn(int j, int i)
   {
      if (i <= 0) return j;
      Funky cls(j,i);
      return fn(j, i-1);
   }
intfn(intj,inti)
{

如果(我相信ICC会这么做。据我所知,ICC生产的代码是市场上最快的。@保罗问题是,ICC代码的速度有多少是由算法优化(如尾部调用优化)引起的,有多少是由缓存和微指令优化引起的,这只有英特尔自己知道他们自己的处理器可以这样做。
gcc
有更窄的选项
-fooptimize sibling calls
“优化sibling and tail recursive calls”。此选项(根据针对不同平台的4.4、4.7和4.8版的
gcc(1)
手册页)在级别
-O2
-O3
-Os
上启用。此外,在调试模式下运行而不明确请求优化将不会进行任何优化。您可以为真正的发布模式EXE启用PDB,并尝试单步执行,但请注意,在发布模式下调试有其复杂性-不可见/剥离变量ABLE、合并变量、变量在未知/意外范围内超出范围、变量永远不会进入范围并成为具有堆栈级地址的真常量,以及-合并良好或缺少堆栈帧。通常合并堆栈帧表示被调用方是内联的,缺少/后向合并的帧可能是尾部调用。您可以激活链接时间虽然是优化,但我猜即使是
extern
方法也可能是内联的。奇怪。我刚刚测试了GCC4.2.3(x86,Slackware 12.1)和GCC4.6.2(AMD64,Debian wheezy),并且使用
-O1
没有内联和尾部递归优化。你必须使用
-O2
(好吧,在4.2.x中,它现在已经相当古老了,它仍然不会被内联)
   int fn(int j, int i)
   {
      if (i <= 0) return j;
      Funky cls(j,i);
      return fn(j, i-1);
   }