4

I am in the process of trying to learn C's more advanced aspects and wrote this when experimenting with the __inline__ keyword:

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

I went to the GNU manuals and found that the -Winline compiler option warns when a function marked __inline__ can't be substituted.

I was indeed expecting a warning, but I compiled this program with gcc -ansi -pedantic -Wall -Wextra -Winline -o test test.c and there were no warnings.

When I ran the program, it printed out the number a whole bunch of times before a segmentation fault, presumably due to the recursion limit being exceeded.

My question is, how does gcc behave in cases like that? If it does inline the functions, how does it know it hit a recursive call between two functions?

Thank you in advance

12
  • 3
    You can look at the output of the compiler: godbolt.org/z/XZ_0NN (Spoiler: endless loop) Commented Apr 8, 2019 at 14:26
  • 1
    Perhaps I'm not understanding the question, but didn't you just find out how gcc behaves in this situation? Commented Apr 8, 2019 at 14:27
  • Do you see the same behavior if you use the standard keyword, inline, instead of the implementation extension, __inline__? Commented Apr 8, 2019 at 14:27
  • @mch Thank you for the resource, I had never come across that tool! Commented Apr 8, 2019 at 14:29
  • 1
    No, @SaucyGoat, __inline__ has never been a keyword of any version of standard C, and it is unlikely to be a keyword of any future version, as its form is reserved for implementation use. Do not confuse implementation extensions (such as __inline__) with standard features, and do not confuse studying the behavior of a specific implementation with studying the behavior required of all conforming implementations. Commented Apr 8, 2019 at 14:37

2 Answers 2

5

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

GCC does not inline any functions when not optimizing unless you specify the ‘always_inline’ attribute for the function

Since you are compiling without optimization, gcc does not even try to inline your functions, hence you do not get a warning that it wasn't done.

When I compile your code with -O -Winline, I get a warning as expected:

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); ^~~~~~ 
Sign up to request clarification or add additional context in comments.

1 Comment

However, if you compile the code with -O2 -Winline, again you get no warning, and the code generated is an infinite loop with the bodies of both f and g inlined into main and no recursive calls. This is because both the call from f to g and the call from g to f are tail recursive so GCC can flatten out the recursion and successfully inline both functions.
2

According to what I see in goldbolt this case the compiler is smart enough to understand that that code is equivalent to a endless loop (see .L2 in the code below). This optimization is possible when recursive functions are tail recursive

This has nothing to do with __inline__. In fact if you remove the __inline__ keyword you get the same optimization and also the assembly code for g and f, which are never 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 

The following compare the assembly generated by gcc with (on the right) and withtout (on the left) __inline__ keyword for g and f. As you can see the main contains exactly the same code. The only difference is that you get additional code for g and f.enter image description here

2 Comments

It has to do with inlining, but not so much with the inline or __inline__ keywords. The compiler is allowed to inline functions even if you don't ask it to.
With -O3, I'm getting an identical (fully inlined) code inside <main>: both with and without removing __inline__ from the source.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.