It’s ok to be curious, but don’t get fixated on this topic. Outside small microcontroller programming it’s going to be of almost no importance. This is not 1980s anymore. What compilers generate, how processors work, and in what way environment affects performance of the program changed greatly in the past four decades. Functions small enough to measurably benefit from either choice are also rare.
If your goal are microcontrollers like AVR, PIC, 8051, then skip my post entirely. There things are a bit different and I can’t give you any advice or explain things better, than what you read so far. Otherwise, if that’s for general programming, continue.
You might’ve heard a story going like this. A “normal” function call “is slow”, because arguments are being put on the stack, then a function is called, then they are taken from the stack, then a result is written, then the func… blebleh. Versus an “inline” function skips all this and “is blazing fast”. Yes, this is how it was with 386 and compilers almost literally replacing C fragments with machine code. Such things don’t exist for 10–20 years.
(1)Nowdays compilers generate machine code independent of the original source code structure, weighting a lot of factors, backed by years of experience. Machines have pipelining, advanced prefetching, caching, speculative execution, can plan and prallelize stuff to avoid idling. Execution environments add their own factors. Not only inlining is done by compilers as needed, just sometimes needing hints from the programmer, but it can have detrimential effect on performance by how it interacts with caches, paging, and branch prediction. Just note how rarely functions are marked as inlined in actual software to get the hint.
(2)Satisfy curiosity and extending general knowledge is great. But to properly understand overhead associated with code using inlining or not, you will need to read the final machine code. And understand how it interacts with the machine and the environment. In 2020s there is no way around this. While a very simplistic code C may give something looking like the 1980-esque description, in general this is not true. For example any sane compiler is going to optimize
tail recursion into something resembling nothing like that. Non-inlined functions will make use of modern calling conventions, inlined functions will get interleaved with surrounding code, a ton of unexpected operations may appear due to non-obvious constraints. And to understand the actual gain (or loss) from inlining it’s crucial to see the call in the context of other instructions.
(1) There do exist “trivial” C compilers. But nobody uses them, if performance is relevant.
(2) And nowadays keyword
inline is not forcing inlining. Compiler-specific features must be used, like GCC’s
always_inline attribute. Otherwise the compiler treats it as a suggestion.