在C中互相调用的2个内联函数的行为

问题描述 投票:3回答:2

我正在尝试学习C的更高级方面,并在尝试使用__inline__关键字时编写了这个:

#include <stdio.h>


void f(int);
void g(int);


__inline__ void f(int egg)
{
    printf("f %d\n", egg);
    g(egg);
}


__inline__ void g(int egg)
{
    printf("g %d\n", egg);
    f(egg);
}


int main()
{
    f(123);

    return 0;
}

我去了GNU手册,发现当标记为-Winline的函数无法替换时,__inline__编译器选项会发出警告。

我确实期待一个警告,但我用gcc -ansi -pedantic -Wall -Wextra -Winline -o test test.c编译了这个程序,没有任何警告。

当我运行程序时,它会在分段错误之前打印出一大堆数字,可能是由于超出了递归限制。

我的问题是,gcc在这样的情况下表现如何?如果它内联函数,它如何知道它在两个函数之间进行递归调用?

先感谢您

c gcc inline
2个回答
5
投票

https://gcc.gnu.org/onlinedocs/gcc-7.4.0/gcc/Inline.html#Inline

除非您为函数指定'always_inline'属性,否则GCC不会在不优化时内联任何函数

由于您在没有优化的情况下进行编译,因此gcc甚至不会尝试内联您的函数,因此您不会收到有关它未完成的警告。

当我使用-O -Winline编译代码时,我收到了预期的警告:

inline.c: In function ‘main’:
inline.c:8:17: warning: inlining failed in call to ‘f’: call is unlikely and code size would grow [-Winline]
 __inline__ void f(int egg)
                 ^
inline.c:24:5: note: called from here
     f(123);
     ^~~~~~

2
投票

根据我在goldbolt中看到的这种情况,编译器足够聪明,可以理解该代码等同于无限循环(参见下面代码中的.L2)。当递归函数是tail recursive时,这种优化是可能的

这与__inline__无关。事实上,如果你删除__inline__关键字,你会得到相同的优化,以及gf的汇编代码,它们永远不会被called。

     .LC0:
            .string "f %d\n"
    .LC1:
            .string "g %d\n"
    main:
            sub     rsp, 8
    .L2:
            mov     esi, 123
            mov     edi, OFFSET FLAT:.LC0
            xor     eax, eax
            call    printf
            mov     esi, 123
            mov     edi, OFFSET FLAT:.LC1
            xor     eax, eax
            call    printf
            jmp     .L2

下面将gcc生成的程序集与(在右侧)和withtout(在左侧)__inline__关键字gf进行比较。如您所见,main包含完全相同的代码。唯一的区别是你得到gf.enter image description here的额外代码

© www.soinside.com 2019 - 2024. All rights reserved.