Frage

Ich habe ein C ++ Programm, das ich mit mingw (gcc für Windows) zu kompilieren. Unter Verwendung der TDM-Version von mingw die 4.4.1 gcc enthält. Die ausführbaren Links zu zwei statische Bibliothek (.a) Dateien: Bei ihnen ist ein Third-Party-Bibliothek in C geschrieben; die andere ist eine C ++ Bibliothek, von mir geschrieben, dass die C-Bibliothek stellt meine eigene C ++ API für verwendet.

Ein (meiner Meinung nach übermäßigem) Teil der Funktionalität der C-Bibliothek wird in Inline-Funktionen implementiert. Sie können mit den Inline-Funktionen nicht vermeiden, wenn Sie die C-Bibliothek API verwenden, aber wenn ich versuche, sie alle zusammen zu verbinden, erhalte ich Linkfehler zu sagen gibt es eine mehr Definition aller der Inline-Funktionen ist - beide, die ich habe rief in meiner C ++ Wrapper-Bibliothek und diejenigen, die ich nicht haben, im Grunde inline definierte etwas in den Headern in einer Funktion erstellt für sie sowohl in der C-Bibliothek und die C ++ Bibliothek bekommen hat.

Es ist nicht mehrere Definitionsfehler verursacht, wenn die Include-Dateien mehrmals in verschiedenen .c oder CPP-Dateien im selben Projekt verwendet werden; das Problem ist nur, dass es eine Definition pro Bibliothek erzeugt.

Wie / warum ist der Compiler in beiden Bibliotheken Funktionen und Symbole für diese Inline-Funktionen zu erzeugen? Wie kann ich sie zwingen, sie in meinem Code zu stoppen zu erzeugen? Gibt es ein Tool kann ich die doppelten Funktionen aus der .a Datei strippen laufen, oder eine Art und Weise des Linker zu machen mehrere Definitionen ignorieren?

(FYI, die Dritte Bibliothek enthält #IFDEF __cplusplus und extern „C“ Wache in all seinen Header, sowieso wenn das das Problem wäre, wäre es nicht mehrere Definition des Symbols führt, wäre es das entgegengesetzte Problem verursachen, weil das Symbol würde nicht definiert oder zumindest anders sein.)

Vor allem die Verbindungsfehler treten nicht auf, wenn ich an die dritte Partei-C-Bibliothek DLL verknüpfen; Ich bekomme aber dann seltsame Laufzeitfehler, die mit meinem Code mit seiner eigenen Version von Funktionen zu haben scheinen zu tun, soll es aus der DLL-Aufruf werden. (Als ob die Compiler lokale Versionen von Funktionen schafft ich nicht gebeten haben.)

Ähnliche Versionen dieser Frage vor gefragt worden, aber ich habe nicht die Antwort auf meine Situation in eine dieser finden:

Die Antwort auf diese Frage war, dass das Plakat mehrfach wurde die Definition Variablen , mein Problem ist, mehrere Definition von Inline-Funktionen: Multiple Definition Fehler wiederholten aus mit gleichen Header in mehrere CPPS-

Dies war ein MSVC Programm, aber ich bin mit mingw; Außerdem wurde das Plakat das Problem in dieser Frage ist die Definition eines C ++ Klassenkonstruktor außerhalb der Klasse Körper in einem Header, während mein Problem mit C-Funktionen ist, die inline sind: Static lib Multiple Definition Problem

Dieser Narr umbenannt alle seinen C-Code als C ++ Dateien und sein C-Code nicht C ++ war - sicher: Multiple Definition von vielen std :: Funktionen bei der Verknüpfung

Dies fehlte nur zu wissen, warum war das eine Definitionsregel verletzt kein Fehler: unvorhersehbares Verhalten von Inline-Funktionen mit unterschiedlichen Definitionen

War es hilfreich?

Lösung

Als erstes müssen Sie das C99 Inline-Modell verstehen - vielleicht gibt es etwas falsch mit Ihrem Header ist. Es gibt zwei Arten von Definitionen für Inline-Funktionen mit externer (nicht statisch) Verknüpfung

  • Externe Definition
    Diese Definition einer Funktion kann nur einmal erscheint im gesamten Programm, in einer bestimmten TU. Es bietet eine exportierte Funktion, die von anderen TUs verwendet werden kann.

  • Inline-Definition
    Diese erscheinen in jeder TU wo als separate Definition erklärt. Die Definitionen tun nicht einander oder mit der externen Definition identisch sein müssen. Wenn in einer Bibliothek intern verwendet, können sie tun auslassen auf Funktionsargumente überprüft, die sonst in der externen Definition durchgeführt werden würde.

Jede Definition der Funktion seine eigenen lokalen statischen Variablen hat , weil ihre lokalen Erklärungen haben keine Verknüpfung (sie in C nicht mit anderen geteilt werden wie ++). Eine Definition einer nicht-statischen Inline-Funktion wird eine Inline-Definition, wenn

sein
  • Jede Funktionsdeklaration in einer TU umfasst die Spezifikations inline und
  • Keine Funktionsdeklaration in einer TU umfasst die Spezifikations extern.

Ansonsten ist die Definition, dass TU erscheinen müssen (weil Inline-Funktionen müssen in der gleichen TU definiert werden, in denen erklärt) ist eine externe Definition. In einem Aufruf an eine Inline-Funktion es ist nicht spezifiziert, ob die externen oder die Inline-Definition verwendet wird . Da jedoch die Funktion in allen Fällen definierte noch das gleiche ist (weil es externe Bindung hat), die Adresse vergleicht sich in allen Fällen gleich, egal wie viele Inline-Definitionen. Also, wenn Sie die Adresse der Funktion übernehmen, ist es wahrscheinlich die Compiler auf die externe Definition löst (vor allem, wenn Optimierungen deaktiviert sind).

Ein Beispiel, das eine falsche Verwendung von inline demonstriert, weil es eine externen Definition einer Funktion zweimal in zwei TUs enthält, ein mehrere Definitionsfehler verursacht

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

Das folgende Programm ist gefährlich, weil der Compiler kostenlos die externe Definition zu verwenden, aber das Programm liefert nicht ein

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

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

Ich habe einige Testfälle mit GCC gemacht, die den Mechanismus zeigen weiter:

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
}

Nun gibt das Programm, was wir erwartet haben!

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

auf der Symboltabelle Sehen, wir werden sehen, dass das Symbol einer Inline-Definition nicht exportiert wird (von main1.o), während eine externen Definition exportiert wird (von main2.o).


Nun, wenn Sie Ihre statischen Bibliotheken jeweils eine externe Definition ihrer Inline-Funktionen haben (wie sie sollten), werden sie natürlich miteinander in Konflikt geraten. Die Lösung ist die Inline-Funktionen statisch oder sie umbenennen zu machen. Diese bieten immer externe Definitionen (also sind sie vollwertige Definitionen), aber sie werden nicht exportiert, weil sie interne Bindung, also nicht in Konflikt

static inline void f(void) {
  printf("i'm unique in every TU\n");
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top