强制内联递归函数

4

考虑经典的阶乘函数定义方法:

#include <stdio.h>

__attribute__((always_inline)) inline int factorial(int n)
{
    if (n == 1){
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

int main()
{
    printf("value %d", factorial(7/*guaranteed to not overflow int*/));
}

我正在强制(gcc)内联阶乘函数。这可能会出问题。gcc在没有错误的情况下忽略了我的强制内联。这是预期的吗?


2
递归函数不能是内联函数。我认为编译器由于这个原因忽略了你的“属性”。 - Astinog
1
@Agostino:如果你看了问题,那么提问者已经知道了,这就是他为什么会问这个问题的原因... - Melkon
由于您使用常量调用了阶乘函数,您怎么知道它没有被内联?我不确定gcc是否那么聪明。在多年前(和版本之前)测试icc时,它并不那么聪明(这种常量优化发生在内联之后而不是与内联混合)。但是也许现在的gcc比当时的icc更聪明。 - JSF
@Agostino 有趣的想法,但我认为内联递归函数可以转换为循环直到某个深度,有效地将递归函数内联(https://dev59.com/Q3VC5IYBdhLWcg3wxEJ1)。 - Floris Velleman
1
@FlorisVelleman 哇,我不知道那个,谢谢。 - Astinog
显示剩余4条评论
1个回答

4

从GCC文档中可以看到:

除非你对某个函数指定了always_inline属性,否则GCC在不优化时不会内联任何函数。

所以always_inline并不是指“内联这个函数或者报错”,而是指“即使关闭了优化也要进行内联”。如果无法或不合理地进行内联,它仍然会拒绝内联该函数。

正如这里所示,对于像您的例子这样简单的函数,整个函数可以进行优化,并在编译时计算结果。即使参数不是编译时常量,该函数仍然可以内联。递归不一定导致无法内联。

但是,正如Floris Velleman所指出的那样,如果你关闭优化,将会无法编译,提示该函数不考虑进行内联,尽管如果开启优化,它会进行内联。看起来实际处理该属性的方式与文档并不完全一致。


1
不错的答案,有趣的是如果你没有进行优化编译,这将导致编译时错误,似乎constexpr更适合处理编译时常量。 - Floris Velleman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接