Is it wrong to place inline functions in C headers?
Asked Answered
D

2

7

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?

Describe answered 20/7, 2017 at 7:25 Comment(8)
"legacy compilers" - But they do support the C99 inline specifier?Seagraves
@StoryTeller: yes, this particular compiler has _inline, but doesn't support pretty much anything from C99 (e.g. variables need to be declared first thing in a scope block).Describe
Well, then I don't think it's possible to predict all issues you may face. If the compiler supports _inline as opposed to the standard inline, you should study the documentation of that compiler specific specifier very carefully.Seagraves
@StoryTeller: Thanks for the pro tip, I actually went and read the pretty short remark in the manual and it states exactly that: "With the _inline keyword, a C function can be defined to be inlined by the compiler. An inline function must be defined in the same source file before it is ’called’. When an inline function has to be called in several source files, each file must include the definition of the inline function. This is typically solved by defining the inline function in a header file." Perhaps you can add an answer with some info anyway?Describe
I would if I had anything meaningful to say :) This compiler specific specifier seems to be about forced inlinling, as opposed to C99's ODR geared inline. So static _inline may be okay. You'd have to examine the generated object files.Seagraves
It's the only place to have them ...Psychosurgery
If you need to force inlining, it might be better to use the #define foo(bar) do { int internal_##bar = bar; ... } while(0) construct, i.e. perform the inlining within the preprocessor. Cause compilers are allowed to entirely ignore inline as they please.Repose
@cmaster: I take your point but I would argue that if you are trusting your compiler with generating specific low-level code without touching specific reserved registers, then you need a detailed understanding and guarantees of the compiler implementation specifics in any event. In which case trusting to inlining behavior is little different from other code generation specifics being relied upon, and there is also little point to avoiding extensions forcing the required behavior. Note that some embedded compilers optimize for size by splitting off common code into sub-functions.Triboluminescence
B
6

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.

Barbecue answered 20/7, 2017 at 7:51 Comment(1)
C99 does provide a mechanism for avoiding duplicated non-inlined instances through the extern inline construct, manually instantiating the fallback function definition into a single compilation unit. In which case plain inline is also to be used in place of static inline for the declaration. Actually, even without inlining allowing the compiler to see the function definition can be a significant performance win, permitting reasoning about the function such as hoisting a constant result out of a loop or the like.Triboluminescence
T
3

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

Toneless answered 20/7, 2017 at 8:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.