29

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

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
mousomer
  • 2,632
  • 2
  • 24
  • 25

3 Answers3

32

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 an extern declaration and you use the function pointer in one compilation unit.
  • tcc just ignores the inline keyword
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • The 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. – Lindydancer Mar 08 '11 at 08:23
  • @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. – Jens Gustedt Mar 08 '11 at 08:30
  • Thanks Jens. It worked (gcc 4.4.5 with flags std=gnu99 and std=c99). – mousomer Mar 08 '11 at 08:54
  • @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? – mpontillo Oct 04 '12 at 00:01
  • @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 as `static 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. – Jens Gustedt Oct 04 '12 at 06:41
  • @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. – mpontillo Oct 04 '12 at 16:09
  • Are 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: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf I might be wrong, however. – Ricardo Sanchez-Saez Feb 18 '13 at 14:51
  • @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. – Jens Gustedt Feb 18 '13 at 15:11
  • Ok, 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: http://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration `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 Feb 18 '13 at 16:38
  • Also, 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. – Ricardo Sanchez-Saez Feb 18 '13 at 16:40
  • @rsanchezsaez, if you write the implementation in the .c `inline` makes no sense anymore. The important thing with `inline` 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 Feb 18 '13 at 17:05
  • @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 the `inline`) into an external definition. Standardeeze is a dialect of English that is not always easy to capture :) – Jens Gustedt Feb 18 '13 at 17:09
  • Thanks for the clarifications. Good point about 'standardeeze', heh. Now I start to understand these issues. ;-) – Ricardo Sanchez-Saez Feb 18 '13 at 17:25
  • To wrap this interesting discussion up, I will leave here this [informative explanation](http://www.greenend.org.uk/rjk/tech/inline.html) 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 Feb 18 '13 at 17:40
  • @Jens: I'm back again. I discovered that some [linkers can inline functions from separate object files](http://stackoverflow.com/questions/5987020/can-the-linker-inline-functions). 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. – Ricardo Sanchez-Saez Feb 21 '13 at 11:03
  • `// 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`? – chux - Reinstate Monica Apr 22 '20 at 19:31
  • @chux You made me edit a 9 year old answer, amazing! – Jens Gustedt Apr 22 '20 at 21:03
  • [LSNED](https://www.urbandictionary.com/define.php?term=LSNED) * 9 * 365 ---> we should all be like [Marvin](https://www.youtube.com/watch?v=1jLIRJwfZhg) by now. – chux - Reinstate Monica Apr 22 '20 at 21:06
  • Your 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 Jan 25 '21 at 16:33
  • I 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. – rosshjb Jan 25 '21 at 16:39
6

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

JonathonW
  • 857
  • 7
  • 17
  • The 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 as `extern`, which would account for this. – Lindydancer Mar 08 '11 at 08:21
-1

I think you don't need to use the inline word when you are defining and declaring the function inside the Header file, the compiler usually takes it as inline by default unless it's too long, in which case it will be smart enough to treat it as a normal function.

I think the multiple definition may be caused by the lack of a Include Guard in the Header file.

You should use something like this in the header:

#ifndef HEADERNAME_H
#define HEADERNAME_H

void func()
{
    // do things...
}

#endif
Emmanuel Valle
  • 332
  • 1
  • 10
  • The 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 Mar 08 '11 at 08:45