13

I have the following three files:

inline_header.h

#ifndef INLINE_HEADER_H
#define INLINE_HEADER_H

inline int func1() {
    return 1;
}

#endif

source1.c

#include "inline_header.h"

source2.c

#include "inline_header.h"

int main() {
    func1();
}

When I compile just source2.c with gcc source2.c it compiles. However, when I attempt to compile with gcc source1.c source2.c I get the a multiple definition error as follows:

/tmp/cchsOaHF.o: In function `func1':
source2.c:(.text+0x0): multiple definition of `func1'
/tmp/ccEyUW0T.o:source1.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status

I am compiling with gcc 4.8.4 on Ubuntu 14.04.

I've tried looking this up and found a similar question multiple definition of inline function. However in his case, the error is caused by a redefinition of his inline function. In my case, I am not redefining it (or at least not explicitly...).

Community
  • 1
  • 1
kevinAlbs
  • 1,114
  • 2
  • 11
  • 20
  • 1
    See [Is `inline` without `static` or `extern` ever useful in C99?](https://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99) – Jonathan Leffler Jan 25 '16 at 17:00

2 Answers2

25

When you compile source1.c into source1.o, it contains a definition of func1. Similarly, when you compile source2.c into source2.o, it also contains a definition of func1. So when you link source1.o and source2.o, you get a multiple definition error.

The reason the include guards don't prevent this is because source1.c and source2.c are each compiled separately. Include guards only help within a single compilation unit.

If this were not an inline function, you'd put a declaration in the header file:

int func1();

Then put the definition in exactly one source file.

However, you're defining the function as inline. So you need to also declare it as static so that each compilation unit gets its own copy of the function.

EDIT:

The multiple definition error is happening because you're compiling in C89 mode by default, and inline isn't part of that version of the standard. As such, it seems that gcc is basically ignoring that keyword.

If you compile in C99 or C11 mode using -std=c99 or =std=c11 with this code, you'll actually get an "undefined reference" error. Section 6.7.4p7 of the C standard states the following:

Any function with internal linkage can be an inline function. For a function with external linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function,and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition

What this means is that a function with only inline doesn't actually provide a definition of a function that can be called. In your case, you want to add the static storage class specifier to force a local definition in each file.

Interestingly, if you compile this code as is with -O1 and -std=c99, gcc will physically inline the function and it will compile and run cleanly.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 1
    Thanks, I was under the impression that the #ifndef guards prevented the header file from being repeated across the entire program. – kevinAlbs Jan 25 '16 at 16:57
  • Doesn’t the behavior described in the OP contradict that inline functions and vars (and not static or locally linked) obey the ODR and therefore can have 1 definition per translation unit as long as they agree? See https://en.cppreference.com/w/cpp/language/inline under ‘Explanation 2’. In fact it needs to be this way since the compiler must see the def in each translation unit as it compiles to inject the function code inline. – Don Slowik Nov 25 '20 at 13:56
  • 2
    @DonSlowik Using `inline` doesn't guarantee that the function is physically inlined. It's only a hint to the complier. Since this is C, you actually want to look at https://en.cppreference.com/w/c/language/inline as well as section 6.7.4 of the C standard. – dbush Nov 25 '20 at 14:03
  • Ahhh, this is C not C++. In C++ it should work fine for the reason I gave. It’s good to know of this difference in behavior between C and C++. – Don Slowik Nov 25 '20 at 14:10
  • 1
    @dbush But then doesn’t the paragraph following the first code example of the link you gave say that the code of the OP should work? The last sentence there seems to say that you can do exactly what the OP code does. – Don Slowik Nov 25 '20 at 14:24
  • 2
    @DonSlowik Actually, it should but it's more complicated than that. OP was compiling in C89 mode. I'll update to reflect. – dbush Nov 25 '20 at 14:59
  • What's happening here is that by default, this version of gcc runs in C89 mode with GNU extensions -- and those GNU extension include a meaning for `inline` that is incompatible with the C99 definition (basically, with the GNU extension, `inline` is the equivalent of the standard `extern inline` while `extern inline` is the equivalent of the standard `inline`). The GNU extension was first, but when it got incorporated into the standard, they decided it made more sense to "reverse" the sense of the `extern` modifier. – Chris Dodd May 08 '23 at 05:34
11

If you wish to place this sort of function in a header, it must also be static:

static inline int func1() {
    return 1;
}

This will cause the symbol to be local to each compilation unit (file), avoiding any linker errors.

Also, from the gcc manual:

When an inline function is not static, then the compiler must assume that there may be calls from other source files; since a global symbol can be defined only once in any program, the function must not be defined in the other source files, so the calls therein cannot be integrated. Therefore, a non-static inline function is always compiled on its own in the usual fashion.

FatalError
  • 52,695
  • 14
  • 99
  • 116