![]() |
1
29
像“C不执行尾部调用消除”这样的语句毫无意义。正如您自己正确指出的,类似这样的事情完全取决于实现。是的,任何合适的实现都可以很容易地将尾部递归变成一个循环。当然,C编译器通常不会对每段特定代码中会发生什么样的优化以及不会发生什么样的优化给出任何保证。你得自己编译看看。 |
![]() |
2
7
尽管现代编译器可能会在启用优化的情况下进行尾部调用优化,但是调试构建可能会在没有它的情况下运行,这样您就可以获得堆栈跟踪、代码的步进/步出以及诸如此类的美妙事情。在这种情况下,不需要尾部调用优化。 由于尾部调用优化并不总是可取的,因此将其委托给编译器编写者是没有意义的。 |
![]() |
3
5
我认为尾部调用优化只需要在
很多
预期的或需要的递归类型;也就是说,在鼓励或实施函数式编程风格的语言中(有了这些语言,你会发现
C编程语言(IMHO)显然是
不
将此与没有
附笔。: 对于 |
![]() |
4
3
回答最后一个问题:标准绝对不应该对优化做任何声明。在有些环境中,实施起来或多或少有点困难。 |
![]() |
5
1
语言标准定义了语言的行为方式,而不是编译器的实现方式。优化不是强制性的,因为它并不总是需要的。编译器提供了一些选项,用户可以在需要时启用优化,也可以关闭优化。编译器优化可能会影响调试代码的能力(以逐行方式将C与程序集匹配变得更加困难),因此仅在用户请求时执行优化是有意义的。 |
![]() |
6
1
对于那些谁喜欢证明建设,这里是godbolt做了一个很好的尾部调用优化和内联: https://godbolt.org/z/DMleUN 但是,如果您将优化设置为-O3(或者如果您等待几年或使用不同的编译器,则毫无疑问),那么优化将完全消除循环/递归。 下面是一个即使使用-O2也可以优化为单个指令的示例: https://godbolt.org/z/CNzWex |
![]() |
7
0
有些情况下,尾部调用优化可能会破坏ABI,或者至少很难以语义保持的方式实现。例如,想想共享库中的位置无关代码:当各种不同的应用程序都依赖于相同的功能时,一些平台允许程序与库动态链接以节省主内存。在这种情况下,库被加载一次并映射到每个程序的虚拟内存中,就好像它是系统上唯一的应用程序一样。在UNIX和其他一些系统上,这是通过对库使用位置无关的代码来实现的,因此寻址是相对于偏移量的,而不是相对于固定地址空间的绝对值。然而,在许多平台上,与位置无关的代码不能进行尾部调用优化。所涉及的问题是,在程序中导航的偏移量必须保存在寄存器中;在Intel 32位上,
其他问题可能在面向对象语言(C++)中清理干净,这意味着函数中的最后一次调用实际上不是最后一次调用——清理是。因此,在这种情况下,编译器通常不会进行优化。
阿尔索
|
![]() |
8
0
编译器通常会识别函数在调用另一个函数后不需要执行任何操作的情况,并用跳转替换该调用。许多情况下,可以安全地做到这一点是很容易识别的,这样的情况有资格作为“安全低挂果实”。然而,即使是在能够执行这种优化的编译器上,当应该或将要执行优化时,也可能并不总是显而易见的。各种因素可能会使尾部呼叫的成本高于正常呼叫的成本,而且这些因素可能并不总是可预测的。例如,如果函数以
如果一种语言有一种特殊的“尾部调用”语法,要求给定的编译器尽可能地进行尾部调用,否则拒绝编译,那么代码可以安全地假定这样的函数可以嵌套任意深。然而,当使用普通的调用语法时,没有通用的方法可以知道编译器是否能够比“普通”编译器更便宜地执行尾部调用。 |
![]() |
Community wiki · C中有哪些耗时的操作? 1 年前 |
![]() |
Community wiki · 将所有处理器电源都投入到任务中 1 年前 |
![]() |
Community wiki · C++为C添加了什么?[已关闭] 1 年前 |
![]() |
Community wiki · 打印1到1000,不带循环或条件 1 年前 |