很简单,什么是尾部调用优化?更具体地说,任何人都可以显示一些可以应用的小代码片段,而不是在哪里,并解释为什么?
language-agnostic algorithm recursion tail-recursion tail-call-optimization
几个星期休息之后,我正在尝试使用David Vandevoorde和Nicolai M. Josuttis 所着的模板 - 完整指南来扩展和扩展我的模板知识,我现在想要了解的是模板的显式实例化.
我实际上并没有这样的机制问题,但我无法想象我想要或想要使用此功能的情况.如果有人能向我解释,我将不仅仅是感激.
使用gcc v4.8.1
如果我做:
//func.hpp
#ifndef FUNC_HPP
#define FUNC_HPP
int func(int);
#endif
//func.cpp
#include "func.hpp"
int func(int x){
return 5*x+7;
}
//main.cpp
#include <iostream>
#include "func.hpp"
using std::cout;
using std::endl;
int main(){
cout<<func(5)<<endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
即使是简单的功能func也不会内联.无相结合inline,extern,static,并__attribute__((always_inline))在样机和/或定义改变了这种(这些说明的一些明显的组合,导致它甚至不会编译和/或产生警告,不谈论那些).我正在使用g++ *.cpp -O3 -o run和g++ *.cpp -O3 -S组装输出.当我看到装配输出时,我仍然看到call func.它似乎只有我能够正确内联函数的方法是拥有原型(可能没有必要)和头文件中函数的定义.如果标题只包含在整个程序中的一个文件中(仅main.cpp作为例子包含),它将编译并且函数将被正确内联,甚至不需要inline符.如果要将标头包含在多个文件中,则inline需要使用说明符来解决多个定义错误,这似乎是其唯一目的.该功能当然可以正确内联.
所以我的问题是:我做错了吗?我错过了什么吗?无论发生什么:
"编译器比你聪明.它知道什么时候应该比你更好地内联函数.永远不要使用C数组.总是使用std :: vector!"
- 每个其他StackOverflow用户
真?所以调用func(5)并打印结果比打印32更快?我会盲目地跟着你离开悬崖的边缘所有人都知道并且所有明智的gcc.
为了记录,上面的代码只是一个例子.我正在写一个光线跟踪器,当我将我的数学和其他实用程序类的所有代码移动到它们的头文件并使用说明inline符时,我看到了大量的性能提升.对于某些场景,字面意思快10倍.
说我有一个功能
void do_something() {
//....
#ifdef FEATURE_X
feature_x();
#endif
//....
}
Run Code Online (Sandbox Code Playgroud)
我可以编译并运行它没有任何问题; 如果我想要我可以通过的功能-D FEATURE_X,它的工作原理.
但是,如果我想do_something放入另一个文件(并且每次我决定更改选项时也不必重新编译该文件)该怎么办?如果它在同一个文件中,我会认为
const int FEATURE_X=0;
void do_something() {
//....
if(FEATURE_X) {
feature_x();
}
//....
}
Run Code Online (Sandbox Code Playgroud)
将正确使用死代码消除,取消呼叫.如果我把它放在另一个文件中,没有LTO,
extern const int FEATURE_X;
void do_something() {
//....
if(FEATURE_X) {
feature_x();
}
//....
}
Run Code Online (Sandbox Code Playgroud)
它不会删除代码(它无法知道).因此,在启用链接时优化的情况下,编译器是否可以检测FEATURE_X链接时的值,确定是否使用了代码,并在适当的情况下将其删除?