inline 函数 multiple define ERROR



I have a C++ program that I compile with mingw (gcc for Windows). Using the TDM release of mingw which includes gcc 4.4.1. The executable links to two static library (.a) files: On of them is a third-party library written in C; the other is a C++ library, written by me, that uses the C library provides my own C++ API on top.

An (in my view, excessive) portion of the C library's functionality is implemented in inline functions. You can't avoid including the inline functions when you use the C library's API, but when I try to link it all together, I'm getting link errors saying there is a multiple definition of all of the inline functions - both ones I have called in my C++ wrapper library and ones which I have not, basically anything defined inline in the headers has gotten a function created for it in both the C library and the C++ library.

It doesn't cause multiple definition errors when the include files are used multiple times in different .c or .cpp files in the same project; the problem is just that it generates one definition per library.

How/why is the compiler generating functions and symbols for these inline functions in both libraries? How can I force it to stop generating them in my code? Is there a tool I can run to strip the duplicate functions from the .a file, or a way to make the linker ignore multiple definitions?

(FYI, the third party library does include #ifdef __cplusplus and extern "C" guards in all its headers; anyway if that were the problem, it would not cause a multiple definition of symbol, it would cause the opposite problem because the symbol would be undefined or at least different.)

Notably, the link errors do NOT occur if I link to the third party C library's DLL; however then I get strange runtime failures that seem to have to do with my code having its own version of functions it should be calling from the DLL. (As if the compiler is creating local versions of functions I didn't ask for.)

Similar versions of this question have been asked before, however, I didn't find the answer to my situation in any of these:

The answer to this question was that the poster was multiply defining variables, my problem is multiple definition of inline functions: http://stackoverflow.com/questions/223771/repeated-multiple-definition-errors-from-including-same-header-in-multiple-cpps

This was an MSVC program, but I'm using mingw; also, the poster's problem in this question was the definition of a C++ class constructor outside of the class body in a header, while my problem is with C functions that are inline: http://stackoverflow.com/questions/717622/static-lib-multiple-definition-problem

This fool renamed all his C code as C++ files and his C code wasn't C++-safe:http://stackoverflow.com/questions/2208834/multiple-definition-of-lots-of-std-functions-when-linking

This one was just wanting to know why violating the one definition rule was not an error:http://stackoverflow.com/questions/2025380/unpredictable-behavior-of-inline-functions-with-different-definitions

share improve this question
 
1 
Notice that C99 inline semantics are different than the one of C++: In C, if one of the inline function declarations is explicitly specified extern, it creates an external definition - which is not an inline definition anymore. These external definitions cannot appear multiple times in the program. In C++ an explicit externon such a function has no effect. You are best off with doing static inline in C. –  ᐅ Johannes Schaub - litb ᐊ  Feb 7 '10 at 17:57
 
Normally inline function definitions are marked as 'weak' symbols and the linker is supposed to remove all duplicates itself. –  Omnifarious  Feb 7 '10 at 18:17
 
Thanks Johannes: using preprocessor definitions, the C library's header files declare these functions "inline" if in the C library's .c files, and "extern inline" when they're in my project. But I'm not sure why they did it that way. The C library does have some code that uses the address of a function as a unique key value. As a C++ programmer I view that as bad practice and I really pray they didn't use the address of an inline function that way. I feel there's almost enough information among these comments to put into an answer, although I still can't compile the program. –  Dennis  Feb 7 '10 at 19:48
 
If it uses the address of the function as a key somewhere and relies on the same address across TUs, you can't use static inline anymore. You could use -fgnu89-inline and use extern inline even in C mode, though (see gcc.gnu.org/onlinedocs/gcc/Inline.html . If you compile without -std=c99, it may even be the mode in effect anyway already, i think). –  ᐅ Johannes Schaub - litb ᐊ  Feb 7 '10 at 20:19
 
I added the "C" tag to this question and (because one cannot have 6 tag) removed the "multiple-definition-error", which seems to be covered by "linker-error" too. –  ᐅ Johannes Schaub - litb ᐊ  May 5 '12 at 15:22

1 Answer

up vote 11 down vote accepted

First you have to understand the C99 inline model - perhaps there is something wrong with your headers. There are two kind of definitions for inline functions with external (non-static) linkage

  • External definition
    This definition of a function can only appear once in the whole program, in a designated TU. It provides an exported function that can be used from other TUs.

  • Inline definition
    These appear in every TU where declared as a separate definition. The definitions do not need to be identical to one another or to the external definition. If used internal in a library, they can do omit checking on function arguments that would otherwise be done in the external definition.

Each definition of the function has its own local static variables, because their local declarations have no linkage (they are not shared like in C++). A definition of a non-static inline function will be an inline definition if

  • Every function declaration in a TU includes the specifier inline, and
  • No function declaration in a TU includes the specifier extern.

Otherwise, the definition that must appear in that TU (because inline functions must be defined in the same TU where declared) is an external definition. In a call to an inline function it's unspecified whether the external or the inline definition is used. However, because the function defined in all cases is still the same (because it has external linkage), the address of it compares equal in all cases, no matter how many inline definitions appear. So if you take the function's address, it's likely the compiler resolves to the external definition (especially if optimizations are disabled).

An example that demonstrates a wrong use of inline, because it includes an external definition of a function twice in two TUs, causing a multiple definition error

// included into two TUs
void f(void); // no inline specifier
inline void f(void) { }

The following program is dangerous, because the compiler is free to use the external definition, but the program does not provide one

// main.c, only TU of the program
inline void g(void) {
  printf("inline definition\n");
}

int main(void) {
  g(); // could use external definition!
}

I have made some test cases using GCC that demonstrate the mechanism further:

main.c

#include <stdio.h>

inline void f(void);

// inline definition of 'f'
inline void f(void) {
  printf("inline def main.c\n");
}

// defined in TU of second inline definition
void g(void);

// defined in TU of external definition
void h(void);

int main(void) {
  // unspecified whether external definition is used!
  f();
  g();
  h();

  // will probably use external definition. But since we won't compare
  // the address taken, the compiler can still use the inline definition.
  // To prevent it, i tried and succeeded using "volatile". 
  void (*volatile fp)() = &f;
  fp();
  return 0;
}

main1.c

#include <stdio.h>

inline void f(void);

// inline definition of 'f'
inline void f(void) {
  printf("inline def main1.c\n");
}

void g(void) {
  f();
}

main2.c

#include <stdio.h>

// external definition!
extern inline void f(void);

inline void f(void) {
  printf("external def\n");
}


void h(void) {
  f(); // calls external def
}

Now, the program outputs what we expected!

$ gcc -std=c99 -O2 main.c main1.c main2.c
inline def main.c
inline def main1.c
external def
external def

Looking at the symbol table, we will see that the symbol of an inline definition is not exported (from main1.o), while an external definition is exported (from main2.o).


Now, if your static libraries each have an external definition of their inline functions (as they should), they will naturally conflict with each other. The solution is to make the inline functions static or just to rename them. These will always provide external definitions (so they are full fledged definitions), but they are not exported because they have internal linkage, thus not conflicting

static inline void f(void) {
  printf("i'm unique in every TU\n");
}
share improve this answer
 
 
This is a very good answer. Unfortunately, I still haven't been able to apply the knowledge to successfully compile my program - attempts to change the extern inlines to static inlines make it fail with the error that it is mixing static and nonstatic definitions of the same function. Perhaps I can use macros in my own code to change the names of the functions where I include the headers, but there are approximately 100 of these things in the headers... –  Dennis  Feb 7 '10 at 22:24
 
For further information, this discussion indicates the compiler optimization level can affect the issue:lkml.indiana.edu/hypermail/linux/kernel/0408.0/1787.html –  Dennis  Feb 7 '10 at 22:25
 
I found something similar when building with MinGW gcc, and discovered that the MinGW headers appear to be incompatible with the -std=gnu99 option. This caused a lot of multiply-defined symbols when I attempted to link, as definitions for the functions were placed in each object file built in this way. –  David Gardner  Mar 28 '12 at 16:02
 
...so I found that using -fgnu89-inline was a suitable workaround for our case, as we needed the gnu99 scoping on for-loop counter variables. (ugh) –  David Gardner  Mar 28 '12 at 16:03

I have a C++ program that I compile with mingw (gcc for Windows). Using the TDM release of mingw which includes gcc 4.4.1. The executable links to two static library (.a) files: On of them is a third-party library written in C; the other is a C++ library, written by me, that uses the C library provides my own C++ API on top.

An (in my view, excessive) portion of the C library's functionality is implemented in inline functions. You can't avoid including the inline functions when you use the C library's API, but when I try to link it all together, I'm getting link errors saying there is a multiple definition of all of the inline functions - both ones I have called in my C++ wrapper library and ones which I have not, basically anything defined inline in the headers has gotten a function created for it in both the C library and the C++ library.

It doesn't cause multiple definition errors when the include files are used multiple times in different .c or .cpp files in the same project; the problem is just that it generates one definition per library.

How/why is the compiler generating functions and symbols for these inline functions in both libraries? How can I force it to stop generating them in my code? Is there a tool I can run to strip the duplicate functions from the .a file, or a way to make the linker ignore multiple definitions?

(FYI, the third party library does include #ifdef __cplusplus and extern "C" guards in all its headers; anyway if that were the problem, it would not cause a multiple definition of symbol, it would cause the opposite problem because the symbol would be undefined or at least different.)

Notably, the link errors do NOT occur if I link to the third party C library's DLL; however then I get strange runtime failures that seem to have to do with my code having its own version of functions it should be calling from the DLL. (As if the compiler is creating local versions of functions I didn't ask for.)

Similar versions of this question have been asked before, however, I didn't find the answer to my situation in any of these:

The answer to this question was that the poster was multiply defining variables, my problem is multiple definition of inline functions: http://stackoverflow.com/questions/223771/repeated-multiple-definition-errors-from-including-same-header-in-multiple-cpps

This was an MSVC program, but I'm using mingw; also, the poster's problem in this question was the definition of a C++ class constructor outside of the class body in a header, while my problem is with C functions that are inline: http://stackoverflow.com/questions/717622/static-lib-multiple-definition-problem

This fool renamed all his C code as C++ files and his C code wasn't C++-safe:http://stackoverflow.com/questions/2208834/multiple-definition-of-lots-of-std-functions-when-linking

This one was just wanting to know why violating the one definition rule was not an error:http://stackoverflow.com/questions/2025380/unpredictable-behavior-of-inline-functions-with-different-definitions

share improve this question
 
1 
Notice that C99 inline semantics are different than the one of C++: In C, if one of the inline function declarations is explicitly specified extern, it creates an external definition - which is not an inline definition anymore. These external definitions cannot appear multiple times in the program. In C++ an explicit externon such a function has no effect. You are best off with doing static inline in C. –  ᐅ Johannes Schaub - litb ᐊ  Feb 7 '10 at 17:57
   
Normally inline function definitions are marked as 'weak' symbols and the linker is supposed to remove all duplicates itself. –  Omnifarious  Feb 7 '10 at 18:17
   
Thanks Johannes: using preprocessor definitions, the C library's header files declare these functions "inline" if in the C library's .c files, and "extern inline" when they're in my project. But I'm not sure why they did it that way. The C library does have some code that uses the address of a function as a unique key value. As a C++ programmer I view that as bad practice and I really pray they didn't use the address of an inline function that way. I feel there's almost enough information among these comments to put into an answer, although I still can't compile the program. –  Dennis  Feb 7 '10 at 19:48
   
If it uses the address of the function as a key somewhere and relies on the same address across TUs, you can't use static inline anymore. You could use -fgnu89-inline and use extern inline even in C mode, though (see gcc.gnu.org/onlinedocs/gcc/Inline.html . If you compile without -std=c99, it may even be the mode in effect anyway already, i think). –  ᐅ Johannes Schaub - litb ᐊ  Feb 7 '10 at 20:19
   
I added the "C" tag to this question and (because one cannot have 6 tag) removed the "multiple-definition-error", which seems to be covered by "linker-error" too. –  ᐅ Johannes Schaub - litb ᐊ  May 5 '12 at 15:22

1 Answer

up vote 11 down vote accepted

First you have to understand the C99 inline model - perhaps there is something wrong with your headers. There are two kind of definitions for inline functions with external (non-static) linkage

  • External definition
    This definition of a function can only appear once in the whole program, in a designated TU. It provides an exported function that can be used from other TUs.

  • Inline definition
    These appear in every TU where declared as a separate definition. The definitions do not need to be identical to one another or to the external definition. If used internal in a library, they can do omit checking on function arguments that would otherwise be done in the external definition.

Each definition of the function has its own local static variables, because their local declarations have no linkage (they are not shared like in C++). A definition of a non-static inline function will be an inline definition if

  • Every function declaration in a TU includes the specifier inline, and
  • No function declaration in a TU includes the specifier extern.

Otherwise, the definition that must appear in that TU (because inline functions must be defined in the same TU where declared) is an external definition. In a call to an inline function it's unspecified whether the external or the inline definition is used. However, because the function defined in all cases is still the same (because it has external linkage), the address of it compares equal in all cases, no matter how many inline definitions appear. So if you take the function's address, it's likely the compiler resolves to the external definition (especially if optimizations are disabled).

An example that demonstrates a wrong use of inline, because it includes an external definition of a function twice in two TUs, causing a multiple definition error

// included into two TUs
void f(void); // no inline specifier
inline void f(void) { }

The following program is dangerous, because the compiler is free to use the external definition, but the program does not provide one

// main.c, only TU of the program
inline void g(void) {
  printf("inline definition\n");
}

int main(void) {
  g(); // could use external definition!
}

I have made some test cases using GCC that demonstrate the mechanism further:

main.c

#include <stdio.h>

inline void f(void);

// inline definition of 'f'
inline void f(void) {
  printf("inline def main.c\n");
}

// defined in TU of second inline definition
void g(void);

// defined in TU of external definition
void h(void);

int main(void) {
  // unspecified whether external definition is used!
  f();
  g();
  h();

  // will probably use external definition. But since we won't compare
  // the address taken, the compiler can still use the inline definition.
  // To prevent it, i tried and succeeded using "volatile". 
  void (*volatile fp)() = &f;
  fp();
  return 0;
}

main1.c

#include <stdio.h>

inline void f(void);

// inline definition of 'f'
inline void f(void) {
  printf("inline def main1.c\n");
}

void g(void) {
  f();
}

main2.c

#include <stdio.h>

// external definition!
extern inline void f(void);

inline void f(void) {
  printf("external def\n");
}


void h(void) {
  f(); // calls external def
}

Now, the program outputs what we expected!

$ gcc -std=c99 -O2 main.c main1.c main2.c
inline def main.c
inline def main1.c
external def
external def

Looking at the symbol table, we will see that the symbol of an inline definition is not exported (from main1.o), while an external definition is exported (from main2.o).


Now, if your static libraries each have an external definition of their inline functions (as they should), they will naturally conflict with each other. The solution is to make the inline functions static or just to rename them. These will always provide external definitions (so they are full fledged definitions), but they are not exported because they have internal linkage, thus not conflicting

static inline void f(void) {
  printf("i'm unique in every TU\n");
}
share improve this answer
 
   
This is a very good answer. Unfortunately, I still haven't been able to apply the knowledge to successfully compile my program - attempts to change the extern inlines to static inlines make it fail with the error that it is mixing static and nonstatic definitions of the same function. Perhaps I can use macros in my own code to change the names of the functions where I include the headers, but there are approximately 100 of these things in the headers... –  Dennis  Feb 7 '10 at 22:24
   
For further information, this discussion indicates the compiler optimization level can affect the issue:lkml.indiana.edu/hypermail/linux/kernel/0408.0/1787.html –  Dennis  Feb 7 '10 at 22:25
   
I found something similar when building with MinGW gcc, and discovered that the MinGW headers appear to be incompatible with the -std=gnu99 option. This caused a lot of multiply-defined symbols when I attempted to link, as definitions for the functions were placed in each object file built in this way. –  David Gardner  Mar 28 '12 at 16:02
   
...so I found that using -fgnu89-inline was a suitable workaround for our case, as we needed the gnu99 scoping on for-loop counter variables. (ugh) –  David Gardner  Mar 28 '12 at 16:03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值