C++ 递归函数可以内联吗?

C++ 递归函数可以内联吗?,c++,c,compiler-construction,C++,C,Compiler Construction,我在阅读时发现,如果编译器不能正确处理上述代码,则会导致“无限编译” 编译器如何决定是否内联一个函数?编译器将生成一个调用图来检测并阻止这些事情。因此,它将看到函数调用自身而不是内联 但它主要由内联关键字和编译器开关控制(例如,即使没有关键字,您也可以让它自动内联小函数)。需要注意的是,调试编译永远不应该内联,因为调用堆栈不会被保留以镜像您在代码中创建的调用。的确,如果您的编译器不能智能地运行,它可能会尝试递归插入内联d函数的副本,从而创建无限大的代码。然而,大多数现代编译器都会认识到这一点。他

我在阅读时发现,如果编译器不能正确处理上述代码,则会导致“无限编译”


编译器如何决定是否内联一个函数?

编译器将生成一个调用图来检测并阻止这些事情。因此,它将看到函数调用自身而不是内联


但它主要由内联关键字和编译器开关控制(例如,即使没有关键字,您也可以让它自动内联小函数)。需要注意的是,调试编译永远不应该内联,因为调用堆栈不会被保留以镜像您在代码中创建的调用。

的确,如果您的编译器不能智能地运行,它可能会尝试递归插入
内联
d函数的副本,从而创建无限大的代码。然而,大多数现代编译器都会认识到这一点。他们可以:

  • 根本不内联函数
  • 将它内联到某个深度,如果到那时它还没有终止,则使用标准函数调用约定调用单独的函数实例。这可以以高性能的方式处理许多常见的情况,同时为具有较大调用深度的罕见情况留下一个后备方案。这也意味着您可以保留该函数代码的内联版本和单独版本

  • 对于案例2,许多编译器都有
    #pragma
    s,您可以设置它来指定执行此操作的最大深度。在gcc中,您还可以使用
    --max inline insns recursive
    (请参阅更多信息)从命令行将其传入;当检测到一个循环在调用它自己时,函数在某个深度之后不再内联(n=1,10,100,无论编译器调整到什么程度)。

    首先,函数的内联规范只是一个提示。编译器可以(并且经常)完全忽略
    内联
    限定符的存在或不存在。也就是说,编译器可以内联递归函数,就像它可以展开无限循环一样。它只需对将“展开”函数的级别设置限制

    优化编译器可能会转换以下代码:

    inline int factorial(int n)
    {
        if(!n) return 1;
        else return n*factorial(n-1);
    }
    
    inline int factorial(int n)
    {
        if (n <= 1)
        {
            return 1;
        }
        else
        {
            return n * factorial(n - 1);
        }
    }
    
    int f(int x)
    {
        return factorial(x);
    }
    
    内联整数阶乘(intn)
    {
    if(n“编译器如何决定是否内联函数?”

    这取决于编译器、指定的选项、编译器的版本号、可用内存量等

    程序的源代码仍然必须遵守内联函数的规则。无论函数是否内联,您都必须为它可能被内联(未知次数)做好准备


    维基百科声明递归宏通常是非法的。C和C++阻止递归调用,但是翻译单元不包含非法代码,因为宏代码看起来像递归的。在汇编程序中,递归宏通常是合法的。

    < P>参见已经给出的答案。解释为什么这通常不起作用

    作为一个“脚注”,你可以通过使用实现你想要的效果(至少是你作为例子使用的阶乘)。从维基百科粘贴:

    int factorial(int n)
    {
        if (n <= 1)
        {
            return 1;
        }
        else
        {
            return n * factorial(n - 1);
        }
    }
    
    int f(int x)
    {
        if (x <= 1)
        {
            return 1;
        }
        else
        {
            int x2 = x - 1;
            if (x2 <= 1)
            {
                return x * 1;
            }
            else
            {
                int x3 = x2 - 1;
                if (x3 <= 1)
                {
                    return x * x2 * 1;
                }
                else
                {
                    return x * x2 * x3 * factorial(x3 - 1);
                }
            }
        }
    }
    
    模板
    结构阶乘
    {
    枚举{value=N*阶乘::值};
    };
    模板
    结构阶乘
    {
    枚举{值=1};
    };
    
    如果可能的话,AFAIK GCC将对递归函数进行尾部调用消除。但是,您的函数不是尾部递归的。

    一些递归函数可以转换为循环,从而有效地无限地内联它们。我相信GCC可以做到这一点,但我不知道其他编译器。

    一些编译器(即Borland C++)不要内联包含条件语句(if、case、while等)的代码,这样示例中的递归函数就不会内联。

    这很可爱,但请注意,原始发布有一个变量参数“int n”。这是真的,但想要“递归内联”也没什么意义当n在编译时不为人所知时…编译器怎么可能做到这一点呢?因此,在这个问题的上下文中,我认为这是一个相关的替代方案。请参阅Derek Park的示例如何做到这一点:通过内联两次,递归n>>两次,结果代码返回2+2。这是“pragma inline_递归”(on)。关于最大深度的文档不一致或不确定。值8、16或#pragma inline_depth的值是可能的。@peterchen如果函数inline正在更改其一个参数的值,我认为最好将函数内联到fact中,而不是main中。很抱歉,我的错误English@obounaim:你可能不会想想看,MSVC没有。
    template <int N>
    struct Factorial 
    {
        enum { value = N * Factorial<N - 1>::value };
    };
    
    template <>
    struct Factorial<0> 
    {
        enum { value = 1 };
    };