C++ Inline Function

What is the use of the `inline` keyword in C?

Note: when I talk about .c files and .h files in this answer, I assume you have laid out your code correctly, i.e. .c files only include .h files. The distinction is that a .h file may be included in multiple translation units.

static inline void f(void) {} has no practical difference with static void f(void) {}.

In ISO C, this is correct. They are identical in behaviour (assuming you don't re-declare them differently in the same TU of course!) the only practical effect may be to cause the compiler to optimize differently.

inline void f(void) {} in C doesn't work as the C++ way. How does it work in C? What actually does extern inline void f(void); do?

This is explained by this answer and also this thread.

In ISO C and C++, you can freely use inline void f(void) {} in header files -- although for different reasons!

In ISO C, it does not provide an external definition at all. In ISO C++ it does provide an external definition; however C++ has an additional rule (which C doesn't), that if there are multiple external definitions of an inline function, then the compiler sorts it out and picks one of them.

extern inline void f(void); in a .c file in ISO C is meant to be paired with the use of inline void f(void) {} in header files. It causes the external definition of the function to be emitted in that translation unit. If you don't do this then there is no external definition, and so you may get a link error (it is unspecified whether any particular call of f links to the external definition or not).

In other words, in ISO C you can manually select where the external definition goes; or suppress external definition entirely by using static inline everywhere; but in ISO C++ the compiler chooses if and where an external definition would go.

In GNU C, things are different (more on this below).

To complicate things further, GNU C++ allows you to write static inline an extern inline in C++ code... I wouldn't like to guess on what that does exactly

I never really found a use of the inline keyword in my C programs, and when I see this keyword in other people's code, it's almost always static inline

Many coders don't know what they're doing and just put together something that appears to work. Another factor here is that the code you're looking at might have been written for GNU C, not ISO C.

In GNU C, plain inline behaves differently to ISO C. It actually emits an externally visible definition, so having a .h file with a plain inline function included from two translation units causes undefined behaviour.

So if the coder wants to supply the inline optimization hint in GNU C, then static inline is required. Since static inline works in both ISO C and GNU C, it's natural that people ended up settling for that and seeing that it appeared to work without giving errors.

, in which I see no difference with just static.

The difference is just in the intent to provide a speed-over-size optimization hint to the compiler. With modern compilers this is superfluous.

C99 inline function in .c file

The inline model in C99 is a bit different than most people think, and in particular different from the one used by C++

inline is only a hint such that the compiler doesn't complain about doubly defined symbols. It doesn't guarantee that a function is inlined, nor actually that a symbol is generated, if it is needed. To force the generation of a symbol you'd have to add a sort of instantiation after the inline definition:

int func(int i);

Usually you'd have the inline definition in a header file, that is then included in several .c files (compilation units). And you'd only have the above line in exactly one of the compilation units. You probably only see the problem that you have because you are not using optimization for your compiler run.

So, your use case of having the inline in the .c file doesn't make much sense, better just use static for that, even an additional inline doesn't buy you much.

Why are C++ inline functions in the header?

The definition of an inline function doesn't have to be in a header file but, because of the one definition rule (ODR) for inline functions, an identical definition for the function must exist in every translation unit that uses it.

The easiest way to achieve this is by putting the definition in a header file.

If you want to put the definition of a function in a single source file then you shouldn't declare it inline. A function not declared inline does not mean that the compiler cannot inline the function.

Whether you should declare a function inline or not is usually a choice that you should make based on which version of the one definition rules it makes most sense for you to follow; adding inline and then being restricted by the subsequent constraints makes little sense.

c++ inline function?

The former (using inline) allows you to put that function in a header file, where it can be included in multiple source files. Using inline makes the identifier in file scope, much like declaring it static. Without using inline, you would get a multiple symbol definition error from the linker.

Of course, this is in addition to the hint to the compiler that the function should be compiled inline into where it is used (avoiding a function call overhead). The compiler is not required to act upon the inline hint.

Is it wrong to place inline functions in C headers?

From n1570 (latest public C11 draft), §6.7.4:


  1. A function declared with an inline function specifier is an inline function. Making a
    function an inline function suggests that calls to the function be as fast as possible. The extent to which such suggestions are effective is implementation-defined.

The next section goes into details about linkage, but this passage above is basically all the C standard has to say about inline. Note how this gives the implementation every freedom, including to completely ignore inline.

Therefore, with just standard C, you could end up with multiple instances (one per translation unit) of a function that is called in the normal way. This is normally not what you want, as it combines two disadvantages (duplicated code and the overhead of a function call). So I'd argue the standard C inline is only ever useful for functions private to a single translation unit. Even then, you could assume a good optimizing compiler will automatically pick candidates for inlining, without an explicit inline.

If on the other hand your compiler provides a way to actually force inlining of a function (which according to your comments, the _inline specifier does for your compiler), having these functions in a header is safe. But be aware it is in no way portable.

As commented by cmaster, you can achieve kind of "manual inlining" with function-like macros instead for a portable solution.

What happens with an extern inline function?

Having added the inline to the function definition in the .c file is just superfluous.

  • Your compilation unit of the .c file sees an extern declaration (without inline) and an inline definition. Thus it emits the symbol for the function in the object file.

  • All other compilation units only see an extern declaration, and so they can use the function without problems, if you link your final executable with the other .o file.

In fact, you just have it the wrong way around. This feature is meant to be used that you have the inline defintion in the .h file, visible to everybody. This definition of the function only acts as a declaration of the symbol, just as extern would, but doesn't define it.

An extern declaration in just one .c file (compilation unit) then ensures such that the symbol is defined, there.

The terminology is a bit confusing, the inline definition acting as declaration of the symbol, and the extern declaration acting as definition of it

C, inline function and GCC

Okay, so after reading through VivienG's link, I think I've understood the exact reasoning behind this error message. It's confusing and misleading (at least to me; it shouldn't happen if you've got just one translation unit), yet it is possible to explain:

  • Assuming the compiler doesn't want to actually inline the code, it has to know where to put that function, especially when it's used in multiple translation units.

  • Classic approach is to create multiple copies, one for each translation unit (or at least for those units where it's used).

  • This may cause problems, e.g. when trying to do some function pointer comparisons (still leaves the question why you'd to that though).

To counter this (and other issues I possibly didn't list here), they've thought of some actually quite neat (although - as mentioned - in my opinion misleading) solution:

You declare the function as inline the way you know, but at the same time you tell the compiler where to put the non-inline version with the extern keyword.

So in your example, you'd keep your function as-is and put it in a header file (so it's known where it's going to be used):

inline int foo(void)
{
return 10 + 3;
}

In addition, to tell the compiler where to place the non-inlined version, you'll have to add one more "forward" declaration in one translation unit:

extern inline int foo(void);

So the whole concept is essentially reversed when compared to classic functions: Put the implementation in the header and then a short declaration in just one file.

As mentioned already, while using the -O3 parameter, all code marked with inline is actually inlined, which won't cause the issue to happen.

When should I write the keyword 'inline' for a function/method?

Oh man, one of my pet peeves.

inline is more like static or extern than a directive telling the compiler to inline your functions. extern, static, inline are linkage directives, used almost exclusively by the linker, not the compiler.

It is said that inline hints to the compiler that you think the function should be inlined. That may have been true in 1998, but a decade later the compiler needs no such hints. Not to mention humans are usually wrong when it comes to optimizing code, so most compilers flat out ignore the 'hint'.

  • static - the variable/function name cannot be used in other translation units. Linker needs to make sure it doesn't accidentally use a statically defined variable/function from another translation unit.

  • extern - use this variable/function name in this translation unit but don't complain if it isn't defined. The linker will sort it out and make sure all the code that tried to use some extern symbol has its address.

  • inline - this function will be defined in multiple translation units, don't worry about it. The linker needs to make sure all translation units use a single instance of the variable/function.

Note: Generally, declaring templates inline is pointless, as they have the linkage semantics of inline already. However, explicit specialization and instantiation of templates require inline to be used.


Specific answers to your questions:

  • When should I write the keyword 'inline' for a function/method in C++?

    Only when you want the function to be defined in a header. More exactly only when the function's definition can show up in multiple translation units. It's a good idea to define small (as in one liner) functions in the header file as it gives the compiler more information to work with while optimizing your code. It also increases compilation time.

  • When should I not write the keyword 'inline' for a function/method in C++?

    Don't add inline just because you think your code will run faster if the compiler inlines it.

  • When will the compiler not know when to make a function/method 'inline'?

    Generally, the compiler will be able to do this better than you. However, the compiler doesn't have the option to inline code if it doesn't have the function definition. In maximally optimized code usually all private methods are inlined whether you ask for it or not.

    As an aside to prevent inlining in GCC, use __attribute__(( noinline )), and in Visual Studio, use __declspec(noinline).

  • Does it matter if an application is multithreaded when one writes 'inline' for a function/method?

    Multithreading doesn't affect inlining in any way.



Related Topics



Leave a reply



Submit