这个问题的标题可能有点奇怪,但问题是,据我所知,根本没有任何反对尾部调用优化的东西。然而,在浏览开源项目时,我已经遇到了一些积极尝试阻止编译器进行尾部调用优化的函数,例如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
}我很想知道为什么这看起来如此重要,有没有任何情况下,我作为一个正常的开发人员也应该记住这一点?例如:尾部调用优化有没有常见的陷阱?
发布于 2012-05-29 06:03:43
我在这里猜测,这是为了确保__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__处于调试目的的堆栈跟踪中。它有支持这一想法的__attribute__((no inline))。
如果你注意到了,这个函数只是跳转到另一个函数,所以它是一种形式的弹床,我只能认为它有一个如此冗长的名称来帮助调试。这将特别有用,因为函数正在调用已从别处注册的函数指针,因此该函数可能无法访问调试符号。
还要注意其他类似命名的函数,它们做类似的事情-它看起来真的很像是为了帮助查看回溯发生了什么。请记住,这是Mac的核心代码,也会出现在崩溃报告和进程示例报告中。
发布于 2012-05-29 05:56:30
这只是一个猜测,但也许是为了避免无限循环与堆栈溢出错误的爆炸。
由于所讨论的方法不会将任何内容放到堆栈上,因此尾部调用递归优化似乎可以生成进入无限循环的代码,而非优化的代码会将返回地址放在堆栈上,在误用的情况下最终会溢出。
我唯一的另一个想法是保留堆栈上的调用,以便进行调试和堆栈跟踪打印。
发布于 2012-05-29 05:59:49
一个潜在的原因是使调试和分析更容易(使用TCO,父堆栈帧消失,这使得堆栈跟踪更难理解)。
https://stackoverflow.com/questions/10790737
复制相似问题