当前位置: 首页 > 知识库问答 >
问题:

void返回型函数的尾部调用优化

颛孙麻雀
2023-03-14

尾部调用优化对返回void的函数的递归调用有效吗?例如,我有一个函数,void fun()

void fun()
{
    ...
    ...
    ...
    fun();
}

在这里,编译器不会知道,调用fun()是最后一条语句。那么尾部调用优化是否只针对返回某些值的函数?

共有1个答案

益明朗
2023-03-14

答案是可以,但编译器没有义务这么做。这在很大程度上取决于函数、编译器和所选的优化级别。如果您关心某个特定函数的这一点,请查看特定编译器在特定优化级别生成的程序集。

更具体地说,GCC(至少是使用LLVM作为后端的苹果版本)将为至少一些返回优化级别-O1或更好的的函数生成尾部调用优化代码。

一些测试代码:

/* Fills an array with a single value, recursively with side effects */
void fillarray(int val, int* curr, int* end)
{
  if (curr==end) return;

  *curr = val;
  fillarray(val,curr+1,end);
}

通过最少的优化(-O1),编译到汇编(gcc-O1-S test.c)会产生一个很好的尾部调用优化函数:

_fillarray:
        pushq       %rbp
        movq        %rsp, %rbp   # set up the stack

        cmpq        %rdx, %rsi   # early exit if beg == end
        je  LBB1_2
LBB1_1:
        movl        %edi, (%rsi) # *curr = val
        addq        $4, %rsi     # curr++

        cmpq        %rsi, %rdx   # TAIL CALL optimization is here
        jne LBB1_1               # if curr != end, go to LBB1_1
LBB1_2:
        popq        %rbp         # restore the stack and exit
        ret

(注意:我已经编辑掉了一些不必要的标签和对齐语句,它们模糊了组件的结构)。

此外,当优化关闭时(-O0),生成的代码是递归的(不是尾部调用优化)。

 类似资料:
  • 我正在学习指针是如何工作的,但我不明白这段代码中的一件事。在void*函数中返回int就像一个咒语,但是返回float就不是了。

  • 我找到了一些很好的SO链接(如何从异步回调函数返回值?以及从node.js中的回调函数返回值等),但它们并不是不能为我的问题提供解决方案。 我的问题:能够得到异步调用的结果,但我如何使用这个结果返回我的函数? 这里获取callBackResponse的值为true或false,并希望将该值用作:

  • 问题内容: 我正在使用Postgresql 8.3,并具有以下简单功能,该功能会将a返回 给客户端 现在,我可以使用以下SQL命令来调用此函数并操纵返回的游标,但是游标名称是由PostgreSQL自动生成的 此外,如38.7.3.5中所述,显式地将游标名称声明为函数的输入参数 。返回游标。我可以声明自己的游标名称并使用此游标名称来操纵返回的游标,而不是为我自动生成的Postgresql吗?如果不是

  • 在C 11中,如何专门化一个函数模板,该模板使用decltype声明为“复杂”的尾部返回类型?以下内容适用于GCC,但在VC2013中产生了“错误C2912:显式专业化‘int f(void)’i不是功能模板的专业化”: 我说“复杂”是因为缺乏一个技术上精确的词,因为我不确定是什么造成了差异。例如,以下decltype使用不依赖于任何函数结果类型的内置操作,可以与模板专业化配合使用: 自动f()-

  • C和C中有没有办法让返回void的函数按照未指定的顺序求值? 我知道函数参数是按未指定的顺序计算的,因此对于不返回void的函数,这可用于以未指定的顺序计算这些函数: 合格编译器编译的合法C和C代码可以按任何顺序打印< code>hi 、< code>bye和< code>moo。这并不是未定义的行为(鼻魔是无效的),有效的输出不止一个,但不一定是无限的,一个兼容的编译器甚至不需要确定它产生了什么

  • 我正在编写自己的编程语言,由于各种原因,它编译为C。(其中之一是我对汇编知之甚少)。 我有一个关于编译器(例如GCC或Clang)如何优化从函数返回值的问题。假设我有这样的代码: 我的理解是,您可能希望变量A在从FUNC返回时复制到B(如果A和B是结构,这可能会很昂贵)。编译器会认识到在这种情况下,B可以指向a所在的位置,而不需要拷贝吗? 如果main()看起来像这样:怎么办? 谢谢大家!