链接静态库时,内联函数的多个定义 [英] Multiple definition of inline functions when linking static libs

查看:1094
本文介绍了链接静态库时,内联函数的多个定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有(GCC对于Windows)C ++程序,我使用MinGW编译。使用MinGW的的TDM版本,其中包括GCC 4.4.1。可执行文件链接到两个静态库(.a)中的文件:在他们的是一个用C写的第三方库;另一种是C ++库,我写的,使用C库提供了在上面我自己的C ++ API。

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.

这是(在我看来,过度)的C库的功能部分内联函数实现的。你无法避免包括您在使用C库的API内联函数,但是当我尝试了一切联系在一起,我收到链接错误说有所有的内联函数的多个定义 - 包括那些我有叫我的C ++封装库而我没有,基本上什么内嵌定义的头已经得到了C函数库和C ++库都为它创建了一个功能的。

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.

这不会导致当包含文件用于在同一项目的不同.C或.cpp文件多次多个定义错误;问题只是,它生成每个库一个定义。

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.

如何/为什么是编译器产生在这两个库,这些内联函数的函数和符号?我怎样才能迫使它停止我的code产生呢?是否有一个工具,我可以运行从某文件剥离重复的功能,或者一种方法,使连接器忽略多个定义?

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?

(仅供参考,第三方库确实包括#IFDEF __cplusplus,并在其所有标题的externC卫士;无论如何,如果是那样的问题,它不会造成符号的多个定义,它会导致相反的问题,因为符号将是不确定的或至少是不同的。)

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

值得注意的是,如果我链接到第三方C库的DLL不发生链接错误;然而,然后我得到的似乎都有自己的就应该从DLL被调用函数的版本我的code做奇怪的运行时故障。 (好像编译器生成的功能我没有要求的本地版本。)

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:

在这个问题的答案是,海报是乘法定义的变量的,我的问题是内联函数的多个定义:<一href=\"http://stackoverflow.com/questions/223771/repeated-multiple-definition-errors-from-including-same-header-in-multiple-cpps\">http://stackoverflow.com/questions/223771/repeated-multiple-definition-errors-from-including-same-header-in-multiple-cpps

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

这是一个MSVC方案,但我使用MinGW的;同时,在这个问题上的海报的问题是一个C ++类的构造函数类体在报头外的定义,而我的问题是与C函数是内联:<一href=\"http://stackoverflow.com/questions/717622/static-lib-multiple-definition-problem\">http://stackoverflow.com/questions/717622/static-lib-multiple-definition-problem

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

这个傻瓜改名为所有的C code作为C ++文件和他的C code为不是C ++ - 安全:<一href=\"http://stackoverflow.com/questions/2208834/multiple-definition-of-lots-of-std-functions-when-linking\">http://stackoverflow.com/questions/2208834/multiple-definition-of-lots-of-std-functions-when-linking

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

此一人只是想知道为什么违反了一个定义的规则是不是一个错误:<一href=\"http://stackoverflow.com/questions/2025380/un$p$pdictable-behavior-of-inline-functions-with-different-definitions\">http://stackoverflow.com/questions/2025380/un$p$pdictable-behavior-of-inline-functions-with-different-definitions

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

推荐答案

首先,你必须了解C99直列模型 - 也许有什么不对您的头。主要存在两种与外部(非静态)联动为内联函数的定义

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


  • 外部定义结果
    一个函数的定义只能在整个程序出现一次,在指定TU。它提供了一个导出的函数,可以从其他的TU使用。

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

函数的定义,每个都有自己的本地静态变量的,因为他们的局部声明没有连接的(它们就象在C不共享++)。非静态的内联函数的定义将是一个内嵌的定义,如果

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


  • 在一个TU每个函数声明包含说明在线

  • 在一个TU没有函数声明包括说明的extern

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

否则,必须出现在TU的定义(因为inline函数必须在宣布同恩定义​​)是外部定义。在到内联函数的的调用它的不确定是否有外部或内联定义用于的。但是,因为在所有情况下所定义的功能仍然是相同的(因为它具有外部连接),它的地址进行比较在所有情况下相等,无论内联定义多少出现。所以,如果你把函数的地址,很可能编译器解析外部定义(特别是如果优化被禁用)。

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!
}

我已经使用GCC进一步证明该机制的一些测试用例:

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

的main.c

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

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

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

综观符号表,我们将看到一个内联定义的符号没有出口(从 main1.o ),而外部定义导出(从 main2.o )。

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");
}

这篇关于链接静态库时,内联函数的多个定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆