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 };
};