Is it wrong to place inline functions in C headers?

4.7k views Asked by At

I am building a C project for several compilers, some of which are legacy compilers which don't seem to have link time inlining support, so it seemed logical to place static inline functions directly in headers and actually have each translation unit have its own copy.

Also, I need to ensure certain functions are inlined so that there are no calls to other functions (i.e. changes to CPU registers) when called inside certain low-level interrupt handlers, so it's not simply about letting the compiler choose if it will affect performance.

However, a colleague of mine told me this is an unusual thing to do and I should avoid it. At this point in project I can probably still rearrange everything, so I would just like to confirm if there are some issues we might face in the long run if we decide to use header inlines?

2

There are 2 answers

1
AudioBubble On BEST ANSWER

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.

0
Serge Ballesta On

According to the comments on the question, defining static _inline functions in header files is the way to go for this specific compiler, the quotation from the compiler doc is clear about that.

The problem you could later face is that it is a specific extension for a specific compiler, distinct from the standard inline specifier. As said by Felix, the standard allows the implementation to choose how it implements inlining, and in particular, ignoring the specifier would still be conformant:

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.

That being said, the semantics seems to the the same (from draft 1256 for C99 or draft 1570 for C11):

6.7.4 Function specifiers
...
Any function with internal linkage can be an inline function. For a function with external linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition

So as common implementations do honour the inline specifier, my opinion is that the risk in portability is limited