Consider the following C++-code with an inline-function:
// this function is in a header-file:
// recursion prevents inlining
inline int calc(int k){
if(k<=1) return 1;
return calc(k-1)+calc(k-2);
}
// this function is in a source-file:
int fun(int k){
return calc(k);
}
Here I use recursion, to simulate the case when compiler was not able to inline the function calc.
The resulting assembly (compiled with -Os, see live on https://godbolt.org/):
...
.weak calc(int)
.type calc(int), @function
calc(int):
// some assembler
.text
.globl fun(int)
.type fun(int), @function
fun(int):
...
jmp calc(int)
As expected, the compiler was not able to inline calc, and thus emitted code for it, but due to inline-keyword it becomes a weak symbol.
Compiling the same code as C, produces a different result (with -Os,see live on https://godbolt.org/):
.Ltext0:
.globl fun
.type fun, @function
fun:
...
jmp calc
The most notable difference: there is no code emitted for calc, so basically the linker will not able to link the executable, as the definition of calc is missing.
Obviously, inline means different things in C compared to C++.
What are differences for inline in C compared to C++? How the definition of calc should be done, that it can be used in a header in C and C++ at the same time?
While the inline-keyword has the same goal in C and C++: to provide the definition of a function at compile time in multiple translation units, these languages use different methods to cope with its fallout - multiple definitions of the same symbol in different translation units.
When the C- or C++-compiler really inlines the inline-function in a translation unit, its definition is no longer needed and no corresponding symbol is emitted. As for example here:
inline int fun(){return 2;}
int doit(){
return fun();
}
the resulting assembler is (live)
doit():
movl $2, %eax
ret
However, when the function don't get inlined, the C++-standard mandates among other things the following:
This more or less describes a weak symbol - and no surprise, C++-compiler emits a weak symbol in the OP's code - it has to, because the C++-standard doesn't guarantee, that this symbol will be defined in another translation unit.
On the other hand, the C-standard gurantees, that the definition of the inline-function must be provided in another translation unit(i.e. has external linkage) and thus (in order to avoid multiple definition of the same symbol) nothing is emited for the inline function - it is just called.
Thus, there must be a c-file, in which the function is "instantiated" via
inline int calc(int k)
This doesn't work well with the idea of having a header-only library. An alternative is, the use internal linkage via static-keyword, i.e.
static inline int calc(int k){
if(k<=1) return 1;
return calc(k-1)+calc(k-2);
}
This will emit a local symbol in every translation unit (if not inlined), independent of whether compiled as C or C++. That means, there are multipe definitions (i.e. in every translation object the function has a different address) of the same function, which will possible lead to a bigger executable, and is a setback for compared to C++-default behavior.
An alternative is to use the following definiton of inline:
#ifdef __cplusplus
#define INLINE inline
#else
#define INLINE static inline
#endif
and use as
INLINE int calc(int k){
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With