I am confused about inline
in C99.
Here is what I want:
.c
file).static inline
).C++ inline
does exactly this.
But (and please correct me if I am wrong) in C99 there is no way to get this behavior.
I could have use static inline
, but it leads to duplication (the address of the same function in different translation unit is not the same). I don't want this duplication.
So, here are my questions:
inline
in C99?References:
inline
, but I don't understand why. Is this “only in exactly one compilation unit” restriction really that nice?inline
. I've read it, but I don't understand it.inline
functions.inline
behavior in C99 (Yes we can)head.h
#ifndef __HEAD_H__
#define __HEAD_H__
inline int my_max(int x, int y) {
return (x>y) ? (x) : (y);
}
void call_and_print_addr();
#endif
src.c
#include "head.h"
#include <stdio.h>
// This is necessary! And it should occurs and only occurs in one [.c] file
extern inline int my_max(int x, int y);
void call_and_print_addr() {
printf("%d %u\n", my_max(10, 100), (unsigned int)my_max);
}
main.c
#include <stdio.h>
#include "head.h"
int main() {
printf("%d %u\n", my_max(10, 100), (unsigned int)my_max);
call_and_print_addr();
return 0;
}
Compile it with: gcc -O3 main.c src.c -std=c99
Check the assembly with: gcc -O3 -S main.c src.c -std=c99
, You'll find that my_max
is inlined in both call_and_print_addr()
and main()
.
Actually, this is exactly the same instructions given by ref 1 and ref 3. And what's wrong with me?
I used a too old version of GCC (3.4.5) to experiment, it give me “multiple definition of my_max
” error message, and this is the real reason why I am so confused. Shame.
inline
Actually you can compile the example above by g++
: g++ main.c src.c
extern inline int my_max(int x, int y);
is redundant in C++, but necessary in C99.
So what does it do in C99?
Again, use gcc -O3 -S main.c src.c -std=c99
, you'll find something like this in src.s
:
_my_max:
movl 4(%esp), %eax
movl 8(%esp), %edx
cmpl %eax, %edx
cmovge %edx, %eax
ret
.section .rdata,"dr"
If you cut extern inline int my_max(int x, int y);
and paste it into main.c
, you'll find these assembly code in main.s
.
So, by extern inline
, you tell the compiler where the true function my_max()
, which you can call it by its address, will be defined and compiled.
Now look back in C++, we can't specify it. We will never know where my_max()
will be, and this is the “vague linkage” by @Potatoswatter.
As is said by @Adriano, most of the time, we don't care about this detail, but C99 really removes the ambiguity.
An inline function is one for which the compiler copies the code from the function definition directly into the code of the calling function rather than creating a separate set of instructions in memory. This eliminates call-linkage overhead and can expose significant optimization opportunities.
Inline Function are those function whose definitions are small and be substituted at the place where its function call is happened. Function substitution is totally compiler choice.
Static inline functions are simple. Either a function defined with the inline function specifier is inlined at a reference, or a call is made to the actual function. The compiler can choose which to do at each reference. The compiler decides if it is profitable to inline at -xO3 and above.
Inlining is the process of replacing a subroutine or function call at the call site with the body of the subroutine or function being called. This eliminates call-linkage overhead and can expose significant optimization opportunities.
To get C++-like behavior, you need to give each TU with potentially-inlined calls an inline
definition, and give one TU an externally-visible definition. This is exactly what is illustrated by Example 1 in the relevant section (Function specifiers) of the C standard. (In that example, external visibility is retroactively applied to an inline
definition by declaring the function extern
afterward: this declaration could be done in the .c
file after the definition in the .h
file, which turns usual usage on its head.)
If inlining could be accomplished literally everywhere, you wouldn't need the extern
function. Non-inlined calls are used, however, in contexts such as recursion and referencing the function address. You may get "always inline" semantics, in a sense, by omitting the extern
parts, however this can arbitrarily fail for any simple function call because the standard does not demand that a call be inlined just because there is no alternative. (This is the subject of the linked question.)
C++ handles this with the implementation concept of "vague linkage"; this isn't specified in the standard but it is very real, and tricky, inside the compiler. C compilers are supposed to be easier to write than C++; I believe this accounts for the difference between the languages.
I want my function get inlined everywhere, not just limited in one translation unit(or one compile unit, a [.c] file).
With inline you politely ask your compiler to inline your function (if it has time and mood). It's unrelated to one compilation unit, at best it may even get inlined in every single call site and it won't have a body anywhere (and its code will be duplicated everywhere). It's purpose of inlining, speed in favor of size.
I want the address of the function consistent. If I save the address of the function in a function pointer, I want the function callable from the pointer, and I don't want duplication of the same function in different translation unit. (Basically, I mean no 'static inline')
Again you can't. If function is inlined then there is not any function pointer to it. Of course compiler will need a compilation unit where function will stay (because, well yes, you may need a function pointer or sometimes it may decide to do not inline that function in a specific call site).
From your description it seems that static inline
is good. IMO it's not, a function body (when used, see above paragraph) in each compilation unit will lead to code duplication (and problem in comparison of function pointers because each compilation unit will have its own version of your function). It's here that C99 did something pretty good: you declare exactly one place to put function body (when and if required). Compiler won't do it for you (if you ever care about it) and there is nothing left to implementor.
What is idea behind inline in C99?
Pick a good thing (inline functions) but remove ambiguity (each C++ compiler did his own job about where function body has to stay).
What benefits does this design give over C++'s approach?
Honestly I can't see such big problem (even article you linked is pretty vague about this benefit). In a modern compiler you won't see any issue and you will never care about that. Why it's good what C did? IMO because it removed an ambiguity even if - frankly speaking - I'd prefer my compiler does that for me when I don't care about it (99.999%, I suppose).
That said, but I may be wrong, C and C++ have different targets. If you're using C (not C++ without classes and few C++ features) then probably you want to address this kind of details because they matters in your context so C and C++ had to diverge about that. There is not a better design: just different decision for a different audience.
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