What effect does inline have on linkage of functions?
Asked Answered
A

2

19

I was reading ODR and as the rule says "In the entire program, an object or non-inline function cannot have more than one definition" and I tried the following...

file1.cpp

#include <iostream>
using namespace std;

inline int func1(void){ return 5; }
inline int func2(void){ return 6; }
inline int func3(void){ return 7; }
int sum(void);

int main(int argc, char *argv[])
{
    cout << func1() << endl;
    cout << func2() << endl;
    cout << func3() << endl;
    cout << sum() << endl;
    return 0;
}

file2.cpp

inline int func1(void) { return 5; }
inline int func2(void) { return 6; }
inline int func3(void) { return 7; }
int sum(void) { return func1() + func2() + func3(); }

It worked as the rule says. I can have multiple definition of inline functions.

  • What is the difference between non-inline function linkage and inline function linkage?
  • How the linker differentiate between these two?
Angelesangelfish answered 23/9, 2016 at 4:55 Comment(1)
What he quoted says an object or non-inline function cannot have more than one definition.Sori
E
21

Making a function inline does two things (the second point is more relevant to your question):

  1. It is a suggestion by the programmer to the compiler, to make calls to this function fast, possibly by doing inline expansion. Roughly, inline expansion is similar to treating the inline function like a macro, expanding each call to it, by the code of its body. This is a suggestion - the compiler may not (and sometimes cannot) perform various optimizations like that.

  2. It specifies the scope of the function to be that of a translation unit. So, if an inline function appears in foo.cpp (either because it was written in it, or because it #includes a header in which it was written, in which case the preprocessor basically makes it so). Now you compile foo.cpp, and possibly also some other bar.cpp which also contains an inline function with the same signature (possibly the exact same one; probably due to both #includeing the same header). When the linker links the two object files, it will not be considered a violation of the ODR, as the inline directive made each copy of the file local to its translation unit (the object file created by compiling it, effectively). This is not a suggestion, it is binding.

It is not coincidental that these two things go together. The most common case is for an inline function to appear in a header #included by several source files, probably because the programmer wanted to request fast inline expansion. This requires the translation-unit locality rule, though, so that linker errors shouldn't arise.

Edrei answered 23/9, 2016 at 5:21 Comment(4)
I must disagree with point 2: inline does not imply the scope to be a single translation unit. That's the job of static. inline can be defined with or without static. There is a specific exception to the ODR if the same inline function is in multiple translation units, as long as they're all the same. See also en.cppreference.com/w/cpp/language/inline.Complexity
I agree with @Piquan. Inline doesn't make the function local to the translation unit. It just tells the linker to - instead of complaining about multiple definitions - just pick one, discard the others and trust the user that all those functions had the same definition. Otherwise function local statics wouldn't work as expected when they are defined in header files.Usual
@Complexity So in other words, having non-static inlined expressions with different signatures in two translations units will result in an ODR violation error. Correct?Bodice
I'm going to be very careful in my wording here. What you described is an ODR violation, which is an error on the programmer's part. The compiler, in that case, is not required to notice the error or issue an error message. But it may end up doing something different than what you expect. (Incidentally, this is also the case if the signatures are the same but the definitions are different.)Complexity
A
2

What is the difference between non-inline function linkage and inline function linkage?

There is none; see [dcl.inline] note 1

The inline keyword has no effect on the linkage of a function.

However, inline results in a relaxation of the one-definition-rule (ODR):

For any definable item D with definitions in multiple translation units,

  • if D is a non-inline non-templated function or variable, or
  • if the definitions in different translation units do not satisfy the following requirements,

the program is ill-formed; [...]

- [basic.def.odr] p14

In other words, it is possible for an inline function to be defined in multiple translation units (i.e. .cpp files) without getting a linker error. This works because the linker chooses one definition and ignores all others. In other words, an inline function is a weak symbol.

However, [basic.def.odr] defines heavy restrictions. Namely, an inline function needs to be defined exactly the same, token by token, everywhere. For example:

// a.cpp
inline int foo() { return 0; }
// b.cpp
inline long foo() { return 0; }

Such a program is ill-formed, no diagnostic required because the definitions are not identical. The easiest way to ensure that all definitions are identical is by putting them in a header. Headers are copied and pasted into translation units with #include, making it much less likely that you've messed up. See also Why do inline functions have to be defined in a header file?

What about "inlining"?

The compiler will inline functions as an optimization regardless whether inline was used or not. As long as a definition of the function is visible to the compiler, it will perform this optimization.

inline merely provides a hint which contributes to the heuristic which decides whether inlining should take place. See also: Are the "inline" keyword and "inlining" optimization separate concepts?

Anglophile answered 5/1, 2024 at 11:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.