7
votes

Quel est l'effet de déclarer 'extern "c"' dans l'en-tête à une bibliothèque partagée C ++?

basé sur Cette question Je comprends le but de la construction dans la liaison des bibliothèques C avec C ++ Code. Supposons maintenant les éléments suivants:

J'ai une bibliothèque partagée '.so' compilée avec un compilateur C ++. L'en-tête a une "conception Typedef" et un certain nombre de déclarations de fonction. Si l'en-tête comprend la déclaration externe "c" ... xxx

... Quel est l'effet? Spécifiquement, je me demande s'il y a des effets secondaires néfastes de cette déclaration puisque la bibliothèque partagée est compilée comme c ++, pas c.

existe-t-il une raison pour avoir la déclaration externe "C" dans ce cas?


1 commentaires

Votre bibliothèque ne sera-elle appelée que de C ++ ou avez-vous également besoin de votre bibliothèque à appeler de C?


5 Réponses :


5
votes

Lors de la compilation C ++, le nom de la méthode change (Mangling) - et vous ne pourrez pas appeler cette méthode à partir d'une autre DLL / EXE qui utilise c.

Pour conserver le nom de la classe et de la méthode dont vous avez besoin pour les compiler comme "C" sans nom de mangling.

La bibliothèque est toujours une bibliothèque C ++, mais elle expose certaines de ses déclarations (l'une dans le bloc externe "C") en tant que méthodes C.


0 commentaires

3
votes

Le #Ifdef gardé externe La déclaration est de dire aux liens C que les symboles ont des entrées de table de symboles C (interdécites). Le #Ifdef garantit qu'il n'y a aucun effet dans l'unité de code (fichier) compilé par un compilateur C.


0 commentaires

12
votes

Ceci est important pour que le compilateur ne nommait pas mangle. C ++ utilise Nom Manglling pour différencier les fonctions avec les surcharges de l'opérateur.

Run "/ usr / bin / nm" contre un binaire pour voir ce que C ++ fait avec vos noms de fonction: _Zst8_destroyin9__GNU_CXX17__NORMAL_CXX17__NORMAL_ITERATORIPIST6VectorIAISAIEEEEVOVT_S7_SAIT0_E

extern "c" empêche ce nom gergling.

IIRC, qui permet au programme de relier dynamiquement des symboles au moment de l'exécution. Il est commun pour les architectures de type "plugin".


1 commentaires

Merci pour l'info. Je pensais à cela de la perspective du client, y compris l'en-tête, et non la bibliothèque exportant les noms.



0
votes

Un détriment à utiliser extern "C" code> pour une API C ++ est qu'il vous empêche d'avoir des surcharges de fonction:

extern "C"
{
    // ILLEGAL - C linkage does not support function overloading
    void foo(int x);
    void foo(const char *str);
}


2 commentaires

Le point d'utilisation externe "c" est destiné à la fois C et C ++ pour partager une API, et c est le dénominateur commun le plus bas, vous devez donc respecter les règles du compilateur C. Si cela était a une API C ++, vous n'utiliseriez pas extern "c" et seulement compiler avec un compilateur C ++ et tout irait bien.


@quamrana - et sa question est "Quel est l'effet à une bibliothèque partagée C ++". Il n'est pas clair de la question s'il doit pouvoir appeler sa bibliothèque du code C.



0
votes

Le #Ifdef Dans l'exemple signifie que seul un compilateur C ++ verra le fichier extern enroulant le fichier d'en-tête qui signifie qu'il produira des noms non mutilés. Un compilateur C ne voit pas le extern (ce qu'il ne comprendrait pas), mais produit toujours des noms non mutilés.

Cela signifie que les compilateurs C et C ++ produiront les mêmes symboles dans leurs fichiers d'objets. Quel que soit le compilateur produit du code d'objet pour les fonctions déclarées, tous les fichiers d'objet seront connectés avec succès car les symboles ont le même lien et le même nom.

Il ne devrait y avoir aucune incidence sur la liaison statique ou la liaison avec une bibliothèque partagée.


0 commentaires