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 withstatic 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 doesextern 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:
- 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 anextern
declaration (withoutinline
) and aninline
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
A How to Create a Matrix in C++
Number of Combinations (N Choose R) in C++
Measure Execution Time in C++ Openmp Code
Round a Float to a Regular Grid of Predefined Points
Linux Allocator Does Not Release Small Chunks of Memory
Calling a Function for Each Variadic Template Argument and an Array
C++ Convert Vector<Int> to Vector<Double>
How to Use Member Initialization List to Initialize an Array
How to Get a Random Element from a C++ Container
What Is a Copy Constructor in C++
Differencebetween a Const Reference and Normal Parameter
Why Is It Illegal to Take the Address of an Rvalue Temporary
Winapi Sleep() Function Call Sleeps for Longer Than Expected