Jus*_*Sid 79 c c++ optimization compiler-optimization tail-call-optimization
这个问题的标题可能有点奇怪,但事实是,据我所知,根本没有什么可以反对尾部调用优化.但是,在浏览开源项目时,我已经遇到了一些主动尝试阻止编译器进行尾调用优化的函数,例如CFRunLoopRef的实现,这些函数充满了这样的黑客攻击.例如:
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline));
static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
if (func) {
func(observer, activity, info);
}
getpid(); // thwart tail-call optimization
}
Run Code Online (Sandbox Code Playgroud)
我很想知道为什么这看起来如此重要,有没有我作为一个普通的开发人员应该保持这种想法呢?例如.尾调用优化有常见的陷阱吗?
mat*_*way 82
我的猜测是,确保__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__在堆栈跟踪中进行调试.它__attribute__((no inline))支持这个想法.
如果你注意到,那个函数只是去反弹到另一个函数,所以它是一种蹦床形式,我只能想到它有一个冗长的名称来帮助调试.这将是特别有用的,因为该函数正在调用已从其他地方注册的函数指针,因此该函数可能没有可访问的调试符号.
还要注意其他类似命名的函数,这些函数执行类似的操作 - 它看起来确实有助于查看从回溯中发生的事情.请记住,这是核心Mac OS X代码,也会出现在崩溃报告和流程样本报告中.
And*_*ite 33
这只是一个猜测,但可能是为了避免无限循环与使用堆栈溢出错误进行轰炸.
由于所讨论的方法没有在堆栈上放置任何内容,因此尾调用递归优化可能会产生进入无限循环的代码,而不是将返回地址放在堆栈上的非优化代码在滥用的情况下最终会溢出.
我唯一的另一个想法是保留堆栈上的调用以进行调试和堆栈跟踪打印.
NPE*_*NPE 21
一个潜在的原因是使调试和分析更容易(使用TCO,父堆栈框架消失,这使得堆栈跟踪更难理解.)