2

I'm not used to C99. I've defined some inline functions in a header file like this:

/* Manhattan distance between (xa, ya) and (xb, yb) */                          
inline int mdistance(pt *a, pt *b) {                                            
  return abs(a->x - b->x) + abs(a->y - b->y);                                     
}

And declared them in the .c for that header file:

extern inline int mdistance(pt *a, pt *b);

However, I need to use those functions in other .c files. I simply included the header file, but it seems I have to declare the "extern inline" in every .c for every inlined function I use. Is that correct? If so, doesn't that miss the point of header files? I ended up with a bunch of .c files including the same header file and also declaring a bunch of redundant "extern inline"s in the beginning. I mean, the definition is in the header file, why would I need to declare it everywhere? PS: Not only that, if I declare one "extern inline" and it uses another inlined function I have to declare "extern inline" for that function too!

Alex
  • 1,416
  • 4
  • 16
  • 42
  • why are you putting `extern inline int mdistance(pt *a, pt *b);` in the .c file ?? – M.M Feb 03 '15 at 20:18
  • 1
    that's what we use include files for. So we don't have to repeat it in every TU – sehe Feb 03 '15 at 20:37
  • 2
    See: [Is `inline` without `static` or `extern` ever useful in C99](http://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99) and [Multiple definition of inline function](http://stackoverflow.com/questions/2722276/multiple-definition-of-inline-function) -- and others. – Jonathan Leffler Feb 03 '15 at 20:42
  • If `inline` is used without `static` or `extern`, then you only need an `extern inline` declaration in one .c file to force the external definition of the function. Not need to put the `extern inline` declarations in all C files. – ouah Feb 03 '15 at 20:44
  • 2
    For my own work, I've adopted a rule that I use `static inline` for functions defined in headers -- AFAIK, that does no harm. The rules on `extern inline` are complicated enough that I'd rather not spend the time learning them. – Jonathan Leffler Feb 03 '15 at 20:44
  • @JonathanLeffler `extern inline` allows you to do some things you cannot do with `static inline`, e. g., take the address of the function. – ouah Feb 03 '15 at 20:47
  • @ouah: possibly...but at that point, I start asking myself 'why' -- why am I inlining a function for which I need to take the address. Like I said, I've been too lazy to learn the details, partly because I've not had a need to learn all the eccentricities that different compilers bring to the table. So far, I've had no problem with `static inline`; that's not to say I'll never need to learn the rest of the ins and outs. – Jonathan Leffler Feb 03 '15 at 20:49
  • @JonathanLeffler another thing I guess is using `extern inline` avoids the possibility to have multiple internal definitions (in different translation units) of the inline function (in case the compiler decide not to inline it) and that would bloat the binary size. But as inline calls are anyway initially intended to be expanded, I'm not sure it's an argument for `extern inline`... – ouah Feb 03 '15 at 20:51
  • Note that it is a good idea to drop the `inline` from `static inline`: With `static` the compiler already knows that the given function is only ever used in the given translation unit and can make a better choice about inlining it than the programmer who adds the `inline` to the definition. Too much inlining hurts performance as much as too little inlining, and most programmers who add the `inline` keyword do not know or test whether inlining that function will indeed speed things up. Of course, if your tests(!) show that `static inline` is faster than `static`, go ahead and use it :-) – cmaster - reinstate monica Feb 03 '15 at 21:31
  • 1
    @cmaster `inline` is only a hint anyway, the compiler can still make the decision – M.M Feb 03 '15 at 21:33
  • @cmaster: the reason for using `static inline` in the header rather than just `static` is that with `static inline` the compiler doesn't need to generate any code if the function is not used, whereas with `static` (only), it is supposed to generate a copy of the function even if it is unused. I suspect it _can_ omit the generated function (I don't think a conforming program could easily spot the presence/absence of the function), but `static inline` explicitly gives it permission to ignore the function when it is unused. It means that 'utility' functions in a header do not bloat the program. – Jonathan Leffler Feb 03 '15 at 22:15
  • @JonathanLeffler The point is, that `static` is actually stronger than `inline`: With `inline` you give a *hint* to the compiler that inlining might be helpful. With `static` the compiler *sees* how many times the function is used. If it's used zero times, the function won't be generated. If it's used once, it will likely be inlined no matter how big it is. If it's used all over the place, the compiler can avoid inlining it even if it's rather short. This is much more valuable information for the inlining decision than a vague hint by a programmer. – cmaster - reinstate monica Feb 04 '15 at 07:08
  • @MattMcNabb I know that `inline` is only a hint. Still, compilers may skew their heuristics due to the presence of `inline` which makes their decision worse than it would have been in the absense of `inline`. The `static` keyword provides much more valuable information to the compiler about that decision (see my reply to Jonathan Leffler for more details). – cmaster - reinstate monica Feb 04 '15 at 07:12

1 Answers1

2

No, you don't need to additionally declare a inline function if it's already defined in header, that is included in every source file.. Consider changing your function to static inline, so compiler doesn't need to worry about external calls:

/* Manhattan distance between (xa, ya) and (xb, yb) */                          
static inline int mdistance(pt *a, pt *b) {                                            
  return abs(a->x - b->x) + abs(a->y - b->y);                                     
}

If such inline function is additionally declared with extern keyword within .c file, then compiler must assume, that it might be called from outside (i.e. from other .c source file) and generate external symbol for it (in simple words compile it as function).

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • The point is in his example (inline without static) he *has* to declare it with `extern inline` in one translation unit to force a definition otherwise he may get a linker error (like undefined reference to the function if the compiler decides not to expand the call). Otherwise I agree it's safe to go with the `static inline` in the header. – ouah Feb 03 '15 at 21:00
  • @ouah: You are right, just checked it by myself. I edited wrong part of my answer leaving `static inline` suggestion. – Grzegorz Szpetkowski Feb 03 '15 at 21:03