multiple definition of inline function - c

I have gone through some posts related to this topic but was not able to sort out my doubt completely. This might be a very naive question.
I have a header file inline.h and two translation units main.cpp and tran.cpp.
Details of code are as below
inline.h
#ifndef __HEADER__
#include <stdio.h>
extern inline int func1(void)
{ return 5; }
static inline int func2(void)
{ return 6; }
inline int func3(void)
{ return 7; }
#endif
main.c
#define <stdio.h>
#include <inline.h>
int main(int argc, char *argv[])
{
printf("%d\n",func1());
printf("%d\n",func2());
printf("%d\n",func3());
return 0;
}
tran.cpp
//(note that the functions are not inline here)
#include <stdio.h>
int func1(void)
{ return 500; }
int func2(void)
{ return 600; }
int func3(void)
{ return 700; }
The above code compiles in g++, but does not compile in gcc (even if you make changes related to gcc like changing the code to .c, not using any C++ header files, etc.). The error displayed is "duplicate definition of inline function - func3".
Can you clarify why this difference is present across compilers?
Also, when you run the program (g++ compiled) by creating two separate compilation units (main.o and tran.o) and create an executable a.out, the output obtained is:
500
6
700
Why does the compiler pick up the definition of the function which is not inline. Actually, since #include is used to "add" the inline definition I had expected 5,6,7 as the output. My understanding was during compilation since the inline definition is found, the function call would be "replaced" by inline function definition.
Can you please tell me in detailed steps the process of compilation and linking which would lead us to 500,6,700 output. I can only understand the output 6.

This answer is divided into the following sections:
How to reproduce the duplicate definition of inline function - func3 problem and why.
Why defintion of func3 is a duplicate instead of func1.
Why it compiles using g++
How to produce the duplicate definition of inline function - func3 problem
The problem can be successfully reproduced by
Rename tran.cpp to tran.c
Compile with gcc -o main main.c tran.c
#K71993 is actually compiling using the old gnu89 inline semantics, which is different from C99. The reason for renaming tran.cpp to tran.c is to tell the gcc driver to treat it as C source instead of C++ source.
Why definition of func3 is a duplicate instead of func1.
GNU 89 inline semantics
The following text is quoted from GCC Document: An Inline Function is As Fast As a Macro explains why func3 is a duplicate definition instead of func1, since func3 (instead of func1) is an externally visible symbol (in GNU89 inline semantics)
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.
If you specify both inline and extern in the function definition, then the definition is used only for inlining. In no case is the function compiled on its own, not even if you refer to its address explicitly. Such an address becomes an external reference, as if you had only declared the function, and had not defined it.
C99 inline semantics
If compiled with C99 standard, i.e., gcc -o main main.c tran.c -std=c99, the linker will complain that definition of func1 is a duplicate due to the reason that extern inline in C99 is a external definition as mentioned in other posts and comments.
Please also refer to this execellent answer about semantic differents between GNU89 inline and C99 inline.
Why it compiles using g++.
When compiled with g++, the source program are considered as C++ source. Since func1, func2 and func3 are defined in multiple translation units and their definitions are different, the One Defintion Rule of C++ is violated. Since the compiler is not required to generate dignostic message when definitions spans multiple translation units, the behavior is undefined.

Maybe you should post the actual code. The snippets you show don't compile:
inline.h has extern inline int func1(void) That doesn't make any sense.
main.h has #define <stdio.h> I think you meant include instead.
Once I fixed those and compiled with gcc, it compiled fine and I got the following output
5
6
7
When I compile with g++, I get this output:
5
6
700
That happens because func3() is not static in inline.h

The compiling error is because there is a duplicate definition of func1();
Because func1() is defined using extern inline, it will produce a external definition.
However, there is also an external definition in tran.c, which cause multiple definition error.
However, func2() and func3() do not produce an external definition, hence no redefinition error.
You might want to look at here http://www.greenend.org.uk/rjk/2003/03/inline.html.
Also, take a note that c++ and c treats inline functions differently, and even in c, different standards (c89 vs. c99) treats inline functions differently.

Your code is invalid from the C++ point of view, since it blatantly violates the One Definition Rule. The only reason you managed to compile it by C++ compiler is the loose error checking in your C++ compiler (it happens to be one of those parts of ODR where "no diagnostic is required").
Your code is not valid C, because it provides duplicate external definition of function func1. Note that it is func1, not func3 that is problematic from the C point of view. There's nothing formally wrong with your func3. Your func2 is also OK, as long as the two definitions never "meet" each other in the same translation unit.
One possible reason you might be getting a different diagnostic report from your compiler is that your C compiler might be supporting inline functions in some non-standard compiler-specific way (either a pre-C99 compiler or a modern compiler run in non-standard "legacy" mode).
Frankly, I find it hard to believe you are getting an error report about func3 from any compiler, assuming the code you posted accurately represents what you are trying to compile. Most likely what you posted is not the real code.

The compile error you see is actually a linker error.
gcc and g++ are treating static inline a little differently. inline was first part of C++ and then made into an extension to many C compilers, before being added to standard C. The standard semantics could be different, but it could just be the implementations that are different.
It could also have something to do with some crazy stuff that happens with C++ code that gets rid of duplicate template stuff catching other duplicate stuff as well.

basically Inline is a late entry to GCC ( I mean c compiler).
"[ . . . ] 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."
— ISO 9899:1999(E), the C99 standard, section 6.7.4

Related

Why do I get a linking error with clang when inlining a function in a C program?

Why doesn't the following program compile with clang?
#include <stdio.h>
inline int f() {
return 42;
}
int main() {
printf("%d\n", f());
}
I get the following:
$ clang -o inline inline.c
Undefined symbols for architecture arm64:
"_f", referenced from:
_main in inline-975155.o
ld: symbol(s) not found for architecture arm64
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)
But I can compile it with clang++ just fine. Is there some nuance between inline in C vs C++?
In C99 you need to provide an alternate (non-inline) definition of the function for when the compiler can't inline. See https://clang.llvm.org/compatibility.html#inline
One of the solutions may work for you, is to make the definition static:
#include <stdio.h>
static inline int f() {
return 42;
}
int main() {
printf("%d\n", f());
}
will work as you expect.
Here are all the options listed in the on the linked clang page:
Change add to a static inline function. This is usually the right solution if only one translation unit needs to use the function. static inline functions are always resolved within the translation unit, so you won't have to add a non-inline definition of the function elsewhere in your program.
Remove the inline keyword from this definition of f. The inline keyword is not required for a function to be inlined, nor does it guarantee that it will be. Some compilers ignore it completely. Clang treats it as a mild suggestion from the programmer.
Provide an external (non-inline) definition of f somewhere else in your program. The two definitions must be equivalent!
Compile in the GNU C89 dialect by adding -std=gnu89 to the set of Clang options. This option is only recommended if the program source cannot be changed or if the program also relies on additional C89-specific behavior that cannot be changed.
In 6.7.4 7, the C 2018 standard says an inline definition does not provide an external definition:
… An inline definition does not provide an external definition for the function…
and that a compiler may use an inline definition or an external definition:
… It is unspecified whether a call to the function uses the inline definition or the external definition.
Thus, a compiler may compile a call to f as a call to the inline definition, which will not result in a link error, or as a call to an external definition, which will result in a link error if you have not provided an external definition. The compiler’s choice may be affected by optimization switches and other settings.
The C++ standard does not have this wording (but I will leave it to others to provide additional interpretation of the C++ standard).
Very simple: Inlining does not work if you do not enable optimizations.
https://godbolt.org/z/KrWq4PGhd
To sort this problem out you need to instruct the compiler to emit not inline version as well:
extern inline int f() {
return 42;
}
Then it will work in both cases (will be inlined or not)
https://godbolt.org/z/dh3G18PqK
CLANG works exactly the same way:
https://godbolt.org/z/ssMnzf5MG
https://godbolt.org/z/ssMnzf5MG

Inline function multiple definition

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...).
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.
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.

C, inline function and GCC [duplicate]

This question already has answers here:
Is "inline" without "static" or "extern" ever useful in C99?
(3 answers)
Closed 8 years ago.
If I have:
inline int foo(void)
{
return 10 + 3;
}
int main(void)
{
foo();
}
with GCC the file compiles well but the linker returns undefined reference to foo
Instead if I remove inline the linker is happy!
It seems as an identifier of an external definition is visible to the linker but
an identifier of an inline definition is not.
Also if I compile with -O3 flag the linker sees the identifier of the inline definition.
What's the problem?
Okay, so after reading through VivienG's link, I think I've understood the exact reasoning behind this error message. It's confusing and misleading (at least to me; it shouldn't happen if you've got just one translation unit), yet it is possible to explain:
Assuming the compiler doesn't want to actually inline the code, it has to know where to put that function, especially when it's used in multiple translation units.
Classic approach is to create multiple copies, one for each translation unit (or at least for those units where it's used).
This may cause problems, e.g. when trying to do some function pointer comparisons (still leaves the question why you'd to that though).
To counter this (and other issues I possibly didn't list here), they've thought of some actually quite neat (although - as mentioned - in my opinion misleading) solution:
You declare the function as inline the way you know, but at the same time you tell the compiler where to put the non-inline version with the extern keyword.
So in your example, you'd keep your function as-is and put it in a header file (so it's known where it's going to be used):
inline int foo(void)
{
return 10 + 3;
}
In addition, to tell the compiler where to place the non-inlined version, you'll have to add one more "forward" declaration in one translation unit:
extern inline int foo(void);
So the whole concept is essentially reversed when compared to classic functions: Put the implementation in the header and then a short declaration in just one file.
As mentioned already, while using the -O3 parameter, all code marked with inline is actually inlined, which won't cause the issue to happen.
You need to pass -std=gnu11 to your compiler.
gcc main. -o main -std=gnu11
EDIT: This post answer lots of questions.
In the C language from C99, if you want an inline function to be used in one compilation unit only, you should declare it as "static inline" and everything will be fine. Otherwise, an inline function that is declared without "static" must be declared as "extern inline" in exactly one compilation unit.
Usually, you will either use "static inline" in a .c file, or you will use "inline" in a .h file and declare the function as "extern inline" in exactly one .c file.
I think user3629249's comment hit the nail on the head. If you compile the code with -O3, the call to foo() is eliminated. i.e., assembly difference:
With -O3:
main:
.LFB4:
.cfi_startproc
xorl %eax, %eax
ret
.cfi_endproc
Without -O3:
main:
.LFB1:
// ...
call foo
// ...
The C standard says in footnote 161 (§6.9/5):
Thus, if an identifier declared with external linkage is not used in
an expression, there need be no external definition for it.
A function at file scope has external linkage but a function declared inline without the extern keyword is an inline definition. In §6.9/5 it says:
An external definition is an external declaration that is also a
definition of a function (other than an inline definition) or an
object. If an identifier declared with external linkage is used in an
expression (other than as part of the operand of a sizeof or
_Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for
the identifier; otherwise, there shall be no more than
one.161)
4 [...] As discussed in 6.7, a declaration that also causes storage to be reserved for an object or a function named by the identifier is a definition.
i.e., using the storage class specifiers static or extern.

Why is static keyword required for inline function?

If I try to compile the following C code without declaring the function static, I get a linker error:
undefined reference to '_fun'
but it works if I don't make it static. In c++, it works just fine without the static keyword.
// Doesn't work
inline int fun()
{
return 3;
}
// Works
static inline int fun()
{
return 3;
}
int main(int argc, const char * argv[])
{
printf("%i", fun());
}
The requirements for inline in C are defined by section 6.7.4 of the ISO C standard. Quoting this section from the N1256
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.
As far as I can tell, your definition satisfies all those requirements. This:
inline int fun()
{
return 3;
}
is both a declaration and a definition of fun. Without the inline keyword, it would have external linkage.
The tricky part is the last sentence:
It is unspecified whether a call to the function uses the inline
definition or the external definition.
In this case, there is no external definition. You don't say what compiler you're using, but gcc -std=c99 -pedantic apparently chooses, by default, to use the external definition, and since there isn't one, you get a linker error. (Without -std=c99 -pedantic, there's no linker error, but that's because gcc also implements inline as an extension on top of C90.)
If you're only going to be using the function in that one source file, you might as well add the static keyword anyway, to give it internal linkage.
And experiment shows that your program compiles, links, and runs correctly if I compile it with optimization, using any of -O1, -O2, or -O3.
A footnote in the C standard seems to imply that gcc is behaving correctly. An example in the same section has a similar non-static inline function definition:
inline double cels(double t)
{
return (5.0 * (t - 32.0)) / 9.0;
}
followed by:
Because cels has external linkage and is referenced, an external
definition has to appear in another translation unit (see 6.9);
the inline definition and the external definition are distinct and
either may be used for the call.
The Standard's intention seems to be that if an inline function has internal linkage, it should be defined just once in the source file that uses it, but if it has external linkage, the inline definition is an alternative to a non-inline definition that must appear elsewhere. The choice of whether to call the external function or expand the inline definition is left to the whim of the compiler.
Some points not directly relevant to your question:
int fun() should probably be int fun(void). The empty parentheses are legal, but they indicate that the function takes an unspecified number and type(s) of arguments. The void specifies that it takes no arguments, which is what you want.
You need #include <stdio.h> if you're going to call printf; this is not optional.
You don't want const in the declaration of argv. For that matter, since you don't refer to the command-line arguments, you can write int main(void).
C99 inline semantics are subtle - in fact, that whole part of the language (storage duration vs linkage, tentative and inline definitions) is a mess.
While inline acts as a compiler hint in definitions that include a storage class specifier (static or extern) and can basically be ignored, the semantics change if no specifier is present.
A definition like inline int fun(void) { ... } does two things:
First, it declares an identifier with external linkage, without providing a corresponding external definition. This means such a definition must be provided by a different translation unit or we end up with undefined behaviour (probably manifesting as failure to link).
Second, it provides an inline definition, which is an alternative to the external one. As the function body is visible in the current translation unit, the compiler may use it to inline the function or for type specialization.
To get the external definition, until fairly recently, I thought it necessary to repeat the function definition in another translation unit (or fake that with 4 lines of preprocessor code).
However, that's not necessary: A single line of code - a re-declaration of the function that includes the extern specifier - is enough to make the inline definition into an external one.
In your example, this would mean putting
inline int foo(void)
{
return 42;
}
into a header file foo.h and providing a source file foo.c with contents
#include "foo.h"
// force definition to be external instead of inline
// I believe inline could be omitted, but it doesn't hurt
extern inline foo(void);
Why is this useful? As C lacks templates, generic code normally comes with a performance penalty as you need to fake generics with void* and function pointers (or, in more complex cases, vtables).
However, a sufficiently smart optimizer can get back most (potentially all) of the performance benefits of templates, but (in the absence of link-time optimization) only if the relevant function definitions are visible in the current translation unit.
While this could be achieved by putting static definitions in headers, this might increase code size to unacceptable levels in the same way that C++ templates might.
In contrast, with a C99 inline function, the compiler is free to ignore the inline definition in favour of the external one, which could even reside in a shared library.
A good example of a function that would benefit from this is qsort(), with an inline definition in stdlib.h and an external one in libc.so. There's no a priori reason for qsort() to be slower than std::sort().

Should an inline function be defined before it is called?

The C language allows source files to be read in a single pass without looking ahead; at any point the compiler only has to consider declarations, prototypes, macro definitions etc. that have appeared before its current position in the file.
Does this mean that for a function call to be inlined, a compiler might require the function to be defined before the call? For example:
int foo(void);
int bar(void) { return foo(); }
inline int foo(void) { return 42; }
Is the call to foo more likely to be inlined if the inline definition is moved in front of the definition of bar?
Should I arrange inline definitions in my code so that they appear before the calls that should best be inlined? Or can I just assume that any optimizing compiler that is advanced enough to do inlining at all will be able to find the definition even if it appears after the call (which seems to be the case with gcc)?
EDIT: I noticed that in the Pelles C with the /Ob1 option indeed requires the definition to visible before a call can be inlined. The Compiler also offers an /Ob2 option which removes this limitation (and also allows the compiler to inline functions without an inline specifier, similar to what gcc does), but the documentation states that using this second option may require much more memory.
It shouldn't make any difference in practice. Because, its compiler's choice to inline a function or not even if it's explicitly told to inline. Compiler may also inline a function even if it's defined using inline keyword.
First, I ran your code with with gcc 4.6.3 without any optimizations:
$ gcc -fdump-ipa-inline test.c
From the generated assembly both foo and bar are not inlined even though foo is inlined.
When I changed put the definition of inline foo at the top, the compiler still didn't inline both.
Next I did the same with -O3:
$ gcc -fdump-ipa-inline -O3 test.c
Now both the functions are inlined. Even though only one has the inline declaration.
Basically the compiler can inline a function as it sees fit.

Resources