How to declare an inline function in C99 multi-file project?
Solution 1
Unfortunately not all compilers are completely complying to C99 in that point even if they claim that they'd be.
An conforming way to do this is
// header file. an inline definition alone is
// not supposed to generate an external symbol
inline void toto(void) {
// do something
}
// in one .c file, force the creation of an
// external symbol
extern inline void toto(void);
Newer versions of gcc, e.g, will work fine with that.
You may get away with it for other compilers (pretenders) by defining something like
#ifdef PRETENDER
# define inlDec static
# define inlIns static
#else
# define inlDec
# define inlIns extern
#endif
// header file. an inline declaration alone is
// not supposed to generate an external symbol
inlDec inline void toto(void) {
// do something
}
// in one .c file, force the creation of an
// external symbol
inlIns inline void toto(void);
Edit:
compilers with C99 support (usually option -std=c99
) that I know of
- gcc (versions >= 4.3 IIRC) implements
the correct
inline
model - pcc is also correct
- ggc < 4.3 needs a special option to implement the correct model, otherwise they use their own model that results in multiple defined symbols if you are not careful
- icc just emits symbols in every unit if you don't take special care. But these symbols are "weak" symbols, so they don't generate a conflict. They just blow up your code.
- opencc, AFAIR, follows the old gcc specific model
- clang doesn't emit symbols for
inline
functions at all, unless you have anextern
declaration and you use the function pointer in one compilation unit. - tcc just ignores the
inline
keyword
Solution 2
If used by itself, in C99 inline
requires that the function be defined in the same translation unit as it's being used (so, if you use it in lib1.c, it must be defined in lib1.c).
You can also declare a method as static inline
(and put the definition in a header file shared between two source files). This avoids the multiple-definition issue, and lets the compiler inline the file across all the translation units where it's used (which it may or may not be able to do if you just declare the function in one translation unit).
See: http://www.greenend.org.uk/rjk/2003/03/inline.html
Related videos on Youtube
mousomer
Things I do: C++, Python, SVM, AI, ML Video compression, Wavelets, General Math, Games theory, Choice theory, Statistical reasoning, Poetry, Cats(x2), Parenting(x2).
Updated on April 23, 2020Comments
-
mousomer about 4 years
I want to define an inline function in a project, compiled with c99. How can I do it? When I declare the function in a header file and give the detail in a .c file, the definition isn't recognized by other files. When I put the explicit function in a header file, I have a problem because all .o files who use it have a copy of the definition, so the linker gives me a "multiple definition" error.
What I am trying to do is something like:
header.h inline void func() { do things... } lib1.c #include "header.h" ... lib2.c #include "header.h"
with a utility which uses both lib1.o and lib2.o
-
Lindydancer over 13 yearsThe term "translation unit" include the source file (lib1.c) and all header files that are included. This means that it should be OK to place it in
header.h
. Either the compiler is broken, or the function is declared asextern
, which would account for this. -
Lindydancer over 13 yearsThe multiple definitions could originate from having an
extern
declaration of the function in a header file. This would force every translation unit to emit a copy of the function. -
Jens Gustedt over 13 years@Lindydancer: sure. But what I say is that some compilers produce the symbol even if you only have
inline
declarations. I'll add some more remarks on specific compilers. -
mousomer over 13 yearsThe funny thing is - the header was guarded by #ifndef. But I think it did.t work because the compiler still put the header in each .o file.
-
mousomer over 13 yearsThanks Jens. It worked (gcc 4.4.5 with flags std=gnu99 and std=c99).
-
mpontillo over 11 years@JensGustedt, is there a benefit to doing this the "new way", as opposed to simply using
static inline
in the header file in all cases? -
Jens Gustedt over 11 years@Mike, yes, in my POV there are two. First you don't blow up your executable with the copies of the function if the compiler decides not to inline. Then, the function is uniquely identifyable by its address, all pointers to it will compare equal, even if they originate in different compilation units. BTW, just declaring it
static
would do exactly the same asstatic inline
,inline
there is almost usesless. Modern compilers don't decide whether or not they inline on their own, programmers are notoriously bad in optimizing that. -
mpontillo over 11 years@Jens, thanks; I was thinking of the case where you'd use this alongside an
always_inline
attribute. In that case it seems like there is no benefit. -
Ricardo Sanchez-Saez over 11 yearsAre you sure this answer is completely correct? If I am understanding the standard correctly, using the non-pretender approach could cause additional problems, such as that if the
toto(void)
function is also defined in a different translation unit, which of the two will be executed is undefined. See 6.7.4-7 and 6.7.4-8 here: open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf I might be wrong, however. -
Jens Gustedt over 11 years@rsanchezsaez, I am not sure if I understand you correctly. But if there are two different definitions of a function in the same compilation unit the behavior is undefined in any case. So no compilation unit that includes the header with the
inline
definition can contain an additional definition. I read the text of the standard that it is undefined if the visible definition is used (either by creating a "secret" local copy or by "inlining" the function) of if just a call to the function symbol is emitted. -
Ricardo Sanchez-Saez over 11 yearsOk, I think you are right and I misread the standard. I don't understand the problem that the example from the sections I pointed out is trying to show. I think my problem lies in that I don't fully understand the difference between declaration and definition. According to this: stackoverflow.com/questions/1410563/…
extern double fahr(double);
should be a declaration. But the standard seems to say that this line is a definition instead. In your example, you seem to use definitions in the header and declarations in the .c. -
Ricardo Sanchez-Saez over 11 yearsAlso, an additional question comes to mind: would it not be clearer to write the function implementation in the .c as
extern inline void toto(void) { // do stuff }
rather than in the .h? Is there any difference in writing the implementation there? Both seem to compile file. -
Jens Gustedt over 11 years@rsanchezsaez, if you write the implementation in the .c
inline
makes no sense anymore. The important thing withinline
is that all translation units see the definition (and it is the same for everyone) and the compiler may decide whether or not put the code in place or to call the function trough the external symbol. -
Jens Gustedt over 11 years@rsanchezsaez, for the declaration versus definition, I don't think that the standard says
extern double fahr(double);
is a definition, but it says that it transforms the internal definition (given with theinline
) into an external definition. Standardeeze is a dialect of English that is not always easy to capture :) -
Ricardo Sanchez-Saez over 11 yearsThanks for the clarifications. Good point about 'standardeeze', heh. Now I start to understand these issues. ;-)
-
Ricardo Sanchez-Saez over 11 yearsTo wrap this interesting discussion up, I will leave here this informative explanation which coincides nicely with your answer and provides further clarification for differences between the C99 and Gnu-C implementations of inline. Jens, thanks for sharing your insights.
-
Ricardo Sanchez-Saez over 11 years@Jens: I'm back again. I discovered that some linkers can inline functions from separate object files. If this is the case, then maybe my suggestion of implementing inline functions in the .c could "work" properly. Anyway, I agree that the safest and most compatible way is the one you propose.
-
chux - Reinstate Monica about 4 years
// header file. an inline declaration alone is
has a function defintion after it. As a definition is also a declaration, does the comment equally apply. Should it be// header file. an inline declaration/definition alone is
? -
Jens Gustedt about 4 years@chux You made me edit a 9 year old answer, amazing!
-
chux - Reinstate Monica about 4 years
-
rosshjb over 3 yearsYour answer helped me. But i think it isn't correct to say "generates/creates an external symbol" for defining external definition(having object code to use for other/itself translation units). A symbol entry is always created in symbol table even if it is not defined at all(The resolution for it would be handled by linker). So, when you have a translation unit containing
inline
only function definition, there is the symbol for it in its object's symbol table. Of course, the symbol is not "defined", but there is. -
rosshjb over 3 yearsI assumed specifically that the inline function call will be compiled to real function call, not inlining in the comment above. When it is compiled to function inlining really, there is no symbol created, because function inlining happened and the function was gone.