Simple explanation of Inline Functions In C

Last year I was working to optimize a (C) code and improve the performance of a product. One of the measures taken was to change simple and small functions which were called numerous times to inline functions.

I know of existence of Inline Functions in C and C++ but not very sure which other languages provide the same.


What are inline functions?


An inline function is a function for which compiler is requested to perform inline expansion i.e. replace the point(s) of invocation with the body of the function. Noticed the highlighted word requested? That’s because it is up to compiler to respect your request. Finally, it may or may not make a function inline.

Why so? I am not sure, may be because compiler considers various factors while making a function inline like size of the function, optimization level, kind of linkage(static or external) and so on. One thing I can surely say is that inlining did work for me and improved some performance. :)


When should inline functions be used?


When there is a time critical function, which is called often and is ceremoniously small in size.


How do inline functions improve performance?


Well, each time a function is called, a significant time is consumed in the call and return mechanism. So, when a function is expanded inline, this overhead is avoided. When it happens multiple times, it results in perceptible performance improvement.


Inline functions vs macros


Now, if you are aware of macros, the obvious question that might be springing in your head would be: Why not use MACROS?

Well, the detailed comparison between inline functions and macros shall take another article. In short, macros are simply textual substitutions and pack many surprises; mostly not the nice ones.

First, as macros are only textual substitution, it may cause unintended results due to order of operations and reevaluation of arguments/statements.

Second, macros do not perform type checking or check if arguments are well formed. This may also cause issues.

Third, unlike inline functions, macros do not maintain value semantics. So, using macros with expressions e.g.  x++ or a+b instead of values may cause unexpected results.

Fourth, macros cannot be used for debugging purpose.

Fifth, macros are always expanded but its decision of expansion of the inline functions rests with compiler. If the function is too big or contain long loops, the compiler may not make it inline.  

Sixth, extra care is required while handling parenthesis. Missing a pair or putting an extra one may cause undesirable results.

There might be few more points that I might not be aware of or able to recollect right now. Feel free to point out in case you find one(or more).


Implementation


Writing an inline function is similar to writing any other function in C. The only extra thing you need to do is use the inline keyword as

inline int max (int x, int y)
{
        return ((x > y)? x : y);
}

It is called as any other function in the following manner:

a = max(a1, a2);

Upon inlining, this statement shall be transformed into:


a = ((a1 > a2)? a1 : a2);

Inline functions and Recursion


When I was using inline functions for the first time, this one popped in my head (which perhaps can make for an interview question!!):

Can a recursive function be written as inline? Will it work or throw error?

So, I just wrote a simple recursive routine print_till_zero(int x) to see if it will work. It did!!

Here’s the code I used:

#include<stdio.h>

inline void print_till_zero(int x)
{
        printf("\n Value of x : %d", x);
        if(x > 0)
                print_till_zero(x-1);
}
int main()
{
        print_till_zero(100);
}

Of course I was not aware that time that the compiler is not bound to oblige to inline keyword and can ignore its presence. So, I tried digging around and this is what I gathered from different sources:
  • Compilers may simply not inline if at least one of the following is true:
    • Function is recursive
    • Function contains loops
    • Function size is too huge
  • A compiler may inline a recursive function but place a limit on the level to which it shall 'unroll' the function. This kind of optimization is done by some compilers. So, if what I understood is correct, the example mentioned above may be transformed into this:
int main()
{
        int x = 100;
        printf("\n Value of x : %d", x);
        if(x > 0)
        {
                x = x-1;
               printf("\n Value of x : %d", x);
               if(x > 0)
               {
                       x = x-1;
                       printf("\n Value of x : %d", x);
                       if (x > 0)
                               print_till_zero(x-1);
               }
        }
}

PS: This example assumes that the compiler is considering the limit as 3.

Inline functions: All Good?


Inline functions kind of live on the edge. Their use might not always be beneficial for the following reasons:

  • A process with a large number of inline functions may end up having a huge code size which can lead to thrashing - a state when large amount of computer resources are used to do minimal amount of work. Reason: Increase in the size of executable may result in more disk operation as the system will end up spending most of the time fetching next chunk of code from the disk. 

On the other hand, inlining may also prevent thrashing. The working set size (number of pages that need to be in memory at once) might go down even if the executable size goes up. When f() calls g(), the code is often on two distinct pages; when the compiler procedurally integrates the code of g() into f(), the code is often on the same page.

  • The increased code size may sometimes cause a critical section of code to no longer fit in the cache resulting in cache misses causing slowdown.
  • In systems like embedded systems where code size is more important than speed, inlining is not generally advantageous.

To wrap up, everything has a bright and a dark side and same holds true for Inline Functions as well. Use them judiciously and you may find a performance improvement but beware of downsides also and just don't rely on them blindly.

comments powered by Disqus