Question

J'ai un programme C ++ que je compiler avec MinGW (gcc pour Windows). Utilisation de la version TDM de MinGW qui comprend gcc 4.4.1. Les liens exécutables à deux fichiers bibliothèque (.a) statique: Sur d'entre eux est une bibliothèque tiers écrit en C; l'autre est une bibliothèque C ++, écrit par moi, qui utilise la bibliothèque C fournit mon propre API C ++ sur le dessus.

An (à mon avis, excessive) partie de la fonctionnalité de la bibliothèque C est mis en œuvre en fonctions en ligne. Vous ne pouvez pas éviter d'inclure les fonctions en ligne lorsque vous utilisez l'API de la bibliothèque C, mais lorsque je tente de lier tous ensemble, je reçois des erreurs de lien disant qu'il ya une définition multiple de toutes les fonctions en ligne - les deux ceux que j'ai appelé dans ma bibliothèque C ++ wrapper et ceux que je ne l'ai pas, essentiellement quoi que ce soit en ligne défini dans les en-têtes a obtenu une fonction créée pour elle à la fois la bibliothèque C et la bibliothèque C ++.

Il ne provoque pas de multiples erreurs de définition lorsque les fichiers inclus sont utilisés plusieurs fois dans différents fichiers .c ou .cpp dans le même projet; le problème est qu'il génère une définition par bibliothèque.

Comment / pourquoi le compilateur génère des fonctions et des symboles pour ces fonctions en ligne dans les deux bibliothèques? Comment puis-je forcer à cesser de les générer dans mon code? Y at-il un outil que je peux courir pour dépouiller les fonctions en double à partir du fichier .a ou un moyen de rendre l'éditeur de liens ignorer plusieurs définitions?

(Pour votre information, la bibliothèque tierce partie ne comprend #ifdef __cplusplus et externat gardes « C » dans tous ses en-têtes, de toute façon, si tel était le problème, il ne causerait pas une définition multiple de symbole, il causerait le problème inverse parce que le symbole serait défini ou au moins différent.)

En particulier, les erreurs de liaison ne se produit pas si je lien vers la DLL du tiers bibliothèque C; Mais je reçois des échecs d'exécution étranges qui semblent avoir à faire avec mon code ayant sa propre version des fonctions qu'il devrait appeler de la DLL. (Comme si le compilateur crée des versions locales des fonctions que je n'ai pas demandé.)

versions similaires de cette question ont déjà été posées, mais je ne l'ai pas trouvé la réponse à ma situation dans l'un de ces:

La réponse à cette question est que l'affiche était de définir multiplier Variables , mon problème est la définition multiple de fonctions en ligne: erreurs répétées multiples Définition d'inclure même en-tête dans plusieurs CPPS

Ce fut un programme MSVC, mais je suis en utilisant MinGW; En outre, le problème de l'affiche dans cette question est la définition d'un constructeur de classe C ++ en dehors du corps de la classe dans un en-tête, alors que mon problème est avec des fonctions C qui sont en ligne: Static Lib multiple Définition problème

Ce fou renommé tout son code C sous forme de fichiers C ++ et son code C ++ C n'a pas été - en toute sécurité: définition multiple des lots de std :: fonctions lors de la liaison

Celui-ci était juste désireux de savoir pourquoi il ne respecte pas la règle d'une définition n'a pas été une erreur: -comportement imprévisible des fonctions en ligne avec des définitions différentes

Était-ce utile?

La solution

D'abord, vous devez comprendre le modèle en ligne C99 - peut-être il y a quelque chose de mal avec vos têtes. Il existe deux types de définitions de fonctions en ligne avec une liaison externe (non statique)

  • Définition externe Cette définition d'une fonction ne peut apparaître qu'une seule fois dans l'ensemble du programme, dans un TU désigné. Il fournit une fonction exportée qui peut être utilisé à partir d'autres TUs.

  • définition en ligne Celles-ci apparaissent dans chaque TU où déclaré une définition distincte. Les définitions ne sont pas doivent être identiques les uns aux autres ou à la définition externe. Si elle est utilisée dans une bibliothèque interne, ils peuvent ne pas omettre de vérifier sur des arguments de fonction qui serait autrement fait dans la définition externe.

Chaque définition de la fonction a ses propres variables statiques locales , parce que leurs déclarations locales ont pas de lien (ils ne sont pas partagés comme en C ++). Une définition d'une fonction en ligne non-statique sera une définition en ligne si

  • Toute déclaration de fonction dans un TU comprend le spécificateur inline et
  • Aucune déclaration de fonction dans un TU comprend le spécificateur extern.

Dans le cas contraire, la définition qui doit apparaître en ce que TU (parce que les fonctions inline doit être défini dans le même TU où déclaré) est une définition externe. Dans un appel à une fonction en ligne il est spécifié si l'externe ou la définition en ligne est utilisé . Cependant, parce que la fonction définie dans tous les cas est toujours le même (parce qu'il a une liaison externe), l'adresse de celui-ci compare l'égalité dans tous les cas, peu importe combien de définitions inline apparaissent. Donc, si vous prenez l'adresse de la fonction, il est probable que le compilateur décide de la définition externe (surtout si les optimisations sont désactivées).

Un exemple qui démontre une mauvaise utilisation de inline, car il comprend une définition externe d'une fonction deux fois en deux Tus provoquant une erreur multiple définition

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

Le programme suivant est dangereux, parce que le compilateur est libre d'utiliser la définition externe, mais le programme ne fournit pas un

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

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

Je l'ai fait quelques cas de test à l'aide du CCG qui démontrent encore le mécanisme:

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
}

Maintenant, le programme génère ce que nous attendions!

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

En regardant la table des symboles, nous verrons que le symbole d'une définition en ligne n'est pas exportée (à partir main1.o), tandis qu'une définition externe est exportée (à partir main2.o).


Maintenant, si vos bibliothèques statiques ont chacun une définition externe de leurs fonctions en ligne (comme ils le devraient), ils entrent en conflit les uns aux autres naturellement. La solution est de rendre les fonctions en ligne statique ou tout simplement pour les renommer. Ceux-ci fournissent toujours des définitions externes (ils sont donc des définitions à part entière), mais ils ne sont pas exportés parce qu'ils ont une liaison interne, donc pas en conflit

static inline void f(void) {
  printf("i'm unique in every TU\n");
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top