Je me demandais récemment quand utiliser C sur C++, et vice versa? Heureusement, quelqu'un m'a déjà batt et bien qu'il a pris un certain temps, j'ai pu digérer toutes les réponses et commentaires à cette question.
Cependant, un élément de ce message continue d'être traité à plusieurs reprises, sans aucun exemple, vérification ou explication:
"Le code C est bon lorsque vous souhaitez avoir plusieurs liaisons de langage pour votre bibliothèque"
Voilà une paraphrase. Je dois noter que plusieurs personnes soulignent que plusieurs liaisons de langage sont possibles en C++ (via un fonctionnement extern
), mais néanmoins, si vous lisez cet article dans son intégralité, il est assez évident que C est idéal pour la portabilité/liaison linguistique. Ma question est: pourquoi?
Quelqu'un peut-il fournir des raisons concrètes pour lesquelles l'écriture de bibliothèques en C permet des liaisons et/ou une portabilité plus faciles dans d'autres langues?
C a une interface beaucoup plus simple et ses règles de conversion d'une interface de code source en une interface binaire sont suffisamment simples pour que la génération d'interfaces externes auxquelles se lier se fasse de manière bien établie. C++, en revanche, a une interface incroyablement compliquée, et les règles de liaison ABI ne sont pas du tout normalisées, ni formellement ni dans la pratique. Cela signifie que pratiquement n'importe quel compilateur pour n'importe quel langage pour n'importe quelle plate-forme peut se lier à une interface C externe et savoir exactement à quoi s'attendre, mais pour une interface C++, c'est essentiellement impossible car les règles changent en fonction du compilateur, de la version et de la version. plate-forme avec laquelle le code C++ a été construit.
En C, il n'y a pas non plus de règles d'implémentation de langage binaire standard, mais c'est un ordre de grandeur plus simple et dans la pratique, les compilateurs utilisent les mêmes règles. Une autre raison qui rend le code C++ difficile à déboguer est la grammaire compliquée mentionnée ci-dessus, car les débogueurs ne peuvent souvent pas gérer de nombreuses fonctionnalités de langage (placer des points d'arrêt dans les modèles, analyser les commandes de transtypage du pointeur dans les fenêtres d'affichage des données, etc.).
L'absence d'une ABI standard (interface binaire d'application) a une autre conséquence - elle rend impossible la livraison des interfaces C++ à d'autres équipes/clients car le code utilisateur ne fonctionnera que s'il est compilé avec les mêmes outils et options de construction. Nous avons déjà vu une autre source de ce problème - l'instabilité des interfaces binaires en raison du manque d'encapsulation au moment de la compilation.
Si vous essayez de communiquer avec un locuteur d'une autre langue, Pidgin est plus facile que l'anglais shakespearien.
Les concepts de C - appels de fonction, pointeurs, chaînes terminées par NULL - sont très simples, donc d'autres langages peuvent facilement les implémenter suffisamment bien pour appeler des fonctions C. Pour des raisons historiques, de nombreux autres langages sont implémentés en C, ce qui rend l'appel des fonctions C encore plus facile.
C++ ajoute pas mal de choses - classes, avec héritage et vtables et modificateurs d'accès; exceptions, avec déroulement de pile et modification du flux de contrôle; modèles. Tout cela rend plus difficile pour les autres langages d'utiliser les liaisons C++: au mieux, il y a plus de "colle" ou de code d'interopérabilité à implémenter, et au pire, les concepts ne se traduisent pas directement (en raison des différences dans les modèles de classe, la gestion des exceptions, etc.). Pour les modèles en particulier, leur simple utilisation (instanciation) nécessite généralement une étape de compilation avec un compilateur C++, ce qui considérablement complique leur utilisation à partir d'autres environnements.
Cela dit, il est possible d'exagérer la difficulté de fournir des liaisons d'une bibliothèque C++ à un autre langage:
extern "C"
, afin que vous puissiez exporter des liaisons de langage de style C (avec toute la simplicité et la compatibilité des liaisons C) à partir d'une bibliothèque C++ (avec la limitation que vous ne pouvez pas exposer de fonctionnalités spécifiques à C++).C est l'une des plus anciennes langues encore présentes. Son ABI est simple, et pratiquement tous les systèmes d'exploitation encore utilisés aujourd'hui y sont écrits . Alors que certains de ces systèmes d'exploitation peuvent avoir ajouté des éléments, par exemple en C # /. NET ou quoi que ce soit en haut, en dessous, ils sont très imprégnés de C.
Cela signifie que, pour utiliser les fonctionnalités fournies par le système d'exploitation, pratiquement tous les langages de programmation moyen d'interfacer avec les bibliothèques C de toute façon . Perl, Java, C++, ils fournissent tous nativement des moyens de "parler C", car ils le devaient s'ils ne voulaient pas réinventer chaque roue il y a.
Cela fait du C le latin des langages de programmation. (Combien d'années d'internet avant que cette métaphore ne soit "l'anglais des langues de programmation"?)
Lorsque vous écrivez votre bibliothèque en C, vous obtenez une interface compatible C gratuitement (évidemment). Si vous écrivez votre bibliothèque en C++, vous pouvez obtenir les liaisons C, via extern "C"
déclarations comme vous l'avez mentionné.
Cependant, vous pouvez obtenir ces liaisons uniquement pour la fonctionnalité qui peut être exprimée en C .
Votre API de bibliothèque ne peut donc pas utiliser ...
Un exemple simple, vous devrez faire en sorte que vos fonctions exportées prennent et retournent tableaux ([]
) au lieu de std::vector
(ou std::string
d'ailleurs).
Donc, non seulement vous ne pourrez pas offrir les bonnes choses que C++ a à offrir aux clients de votre bibliothèque, mais vous devrez également aller à supplémentaires effort pour "traduire" votre API de bibliothèque de C++ en "C compatible" (extern "C"
).
C'est pourquoi le point pourrait être fait que C est le meilleur choix pour implémenter une bibliothèque. Personnellement, je pense que les avantages du C++ l'emportent toujours sur l'effort nécessaire pour un extern "C"
API, mais c'est juste moi.
En laissant de côté les autres réponses déjà fournies:
La raison pour laquelle de nombreux langages fournissent une liaison C est que tous les systèmes d'exploitation * nix et Windows exposent la plupart de leur API de système d'exploitation via une interface C. L'implémentation du langage doit donc déjà s'interfacer avec C pour pouvoir s'exécuter sur les principaux Oses. Par conséquent, il est simple d'offrir également une communication directe avec n'importe quelle interface C à partir du langage lui-même.
Il n'y a pas de raison. Si la sémantique que vous essayez d'exprimer est fondamentalement compatible C et pas quelque chose comme des modèles, il n'y a aucune raison que vous puissiez vous lier plus facilement si l'implémentation est écrite en C. En fait, c'est à peu près par définition = qu'une interface C peut être remplie par n'importe quelle implémentation qui peut respecter le contrat binaire - y compris une implémentation dans un autre langage. Il existe des langages autres que C++ qui peuvent implémenter des contrats binaires C qui peuvent fonctionner de cette façon.
Cela se résume vraiment à des gens qui ne veulent pas apprendre de nouvelles langues ou des idées qui ont une sémantique ou des fonctionnalités réellement utiles, essayant désespérément de choisir une raison de rester à l'ère des dinosaures.
Il existe deux axes principaux lors de l'interfaçage avec une autre langue:
C a un avantage sur C++ sur ces deux fronts:
Maintenant, pourquoi la plupart des langages ont un ensemble de concepts similaire à C peut être dû au fait qu'il soit "simple" ou "préexistant"; cela n'a pas d'importance cependant, le fait est qu'ils le font.
Au contraire, C++ a des concepts complexes, et l'ABI est décidé par chaque compilateur (bien que beaucoup adhèrent à l'Itanimum ABI, sauf sous Windows ...). Herb Sutter a en fait proposé que les systèmes d'exploitation corrigent un ABI C++ (sur une base par système d'exploitation) pour résoudre partiellement ce problème. Aussi, il faut noter qu'un CFI FFI est possible, D le tente3.
1 Sauf variadiques (...
), ce ne sont pas simples
Fondamentalement, cela se résume à la normalisation ABI. Alors que ni C ni C++ n'ont un ABI standardisé que d'autres langages peuvent utiliser pour interfacer entre des binaires écrits, C est devenu une norme de facto, tout le monde le sait et tout le monde peut utiliser les mêmes règles simples que le langage a en ce qui concerne types et appels de fonction.
C++ pourrait avoir un ABI standard, mais Stroustrup a dit qu'il n'en voyait pas la nécessité. Il dit également qu'il serait difficile d'obtenir le consensus des rédacteurs de compilateurs (bien que je doute que - le comité standard C++ émette un ABI similaire à ceux existants et les rédacteurs de compilateurs modifient simplement la prochaine version de leurs compilateurs, qui sont parfois incompatibles avec les binaires construit avec les anciennes versions de leurs compilateurs de toute façon - je me souviens avoir recompilé quelques bibliothèques avec un nouveau compilateur Sun et avoir constaté qu'elles ne fonctionnaient pas avec les anciennes)
Vous remarquerez que certaines entreprises sont passées à l'utilisation d'un ABI standard, Microsoft a commencé ce processus avec COM dans les années 90, et aujourd'hui, elles l'ont affiné dans le WinRT ABI (à ne pas confondre avec l'autre WinRT qui fait référence à un type de table OS) qui permet aux programmes écrits en C # de communiquer avec des bibliothèques écrites en C ou C++ (c'est-à-dire que la propre couche de système d'exploitation de Microsoft est écrite en C++, exposée à l'aide de WinRT et consommée par les applications C # lorsqu'elles appellent n'importe quelle routine d'exécution de système d'exploitation)
Personne ne peut faire grand-chose à moins qu'un organisme de normalisation n'intervienne et ne corrige cette situation. Microsoft y voit évidemment la valeur et a pris des mesures pour la résoudre pour leur plate-forme.
Donc, la réponse est vraiment C ne fait pas fournir des liaisons de langage. Il arrive que personne ne les ait écoutés et les consomme malgré tout.