Pourquoi C fournit-il des «liaisons» de langage là où C ++ est insuffisant?

60

Je me demandais récemment quand utiliser C sur C ++ et vice versa. Heureusement, quelqu'un m'a déjà battu et, bien que cela ait pris du temps, j'ai pu digérer toutes les réponses et commentaires à cette question.

Toutefois, un élément de ce message continue à être traité, sans aucun exemple, vérification ou explication:

"Le code C est utile lorsque vous souhaitez avoir plusieurs liaisons de langue pour votre bibliothèque"

C'est une paraphrase. Je devrais noter que plusieurs personnes soulignent que plusieurs liaisons de langage sont possibles en C ++ (via certains externfonctionnements), mais néanmoins, si vous lisez ce post dans son intégralité, il est assez évident que C est idéal pour la liaison de portabilité / langage. Ma question est: pourquoi?

Quelqu'un peut-il fournir des raisons concrètes pour lesquelles écrire des bibliothèques en C facilite les liaisons et / ou la portabilité dans d'autres langues?

smeeb
la source
6
Principalement pour des raisons historiques et sociales. La plupart des implémentations de langage et des systèmes d'exécution sont construits au-dessus de C. Par exemple, les environnements d'exécution Ocaml, SBCL, Haskell sont codés en C (et ne gagneront pas grand chose en étant recodés en C ++)
Basile Starynkevitch
8
En pratique, il est pénible de coller de véritables bibliothèques C ++ (pensez à Qt) à ces exécutions.
Basile Starynkevitch
3
@Basile: Qt n'est pas une véritable bibliothèque C ++. En outre, même pour les bibliothèques les plus douloureuses, c'est seulement douloureux car elles expriment une sémantique réellement utile.
DeadMG
2
Numéro de téléphone
2
Lire Essential COM par Don Box. Il explique le processus de création d'une ABI en C ++. COM était la manière de Microsoft de créer une ABI. C'est-à-dire que les bibliothèques COM C ++ peuvent être utilisées à partir de C ou de VB ou d'autres langages.
user93353

Réponses:

69

C a une interface beaucoup, beaucoup plus simple, et ses règles pour convertir 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 lie soit faite d’une 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 quasiment n'importe quel compilateur, quel que soit le langage, quelle que soit la 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 standard d'implémentation en langage binaire, mais c'est un ordre de grandeur plus simple et, en pratique, les compilateurs utilisent les mêmes règles. Une autre raison qui rend le code C ++ difficile à déboguer est la grammaire complexe mentionnée ci-dessus, car les débogueurs ne peuvent souvent pas gérer plusieurs fonctionnalités du langage (placer des points d'arrêt dans les modèles, analyser les commandes de transtypage dans les fenêtres d'affichage des données, etc.).

L'absence d'une ABI (interface binaire d'application) standard a une autre conséquence: elle rend impossible la fourniture d'interfaces C ++ à d'autres équipes / clients car le code utilisateur ne fonctionnera pas s'il n'est pas 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 due au manque d’encapsulation lors de la compilation.

- C ++ défectueux

Maçon Wheeler
la source
4
Il est à noter que, s'il est possible de définir une API de type C implémentée en C ++ ( extern "C"il reste encore du travail supplémentaire à faire, elle doit être contrebalancée par les fonctionnalités fournies par C ++)
jhominal
5
L'ABI C ++ n'a aucune importance dans le contexte de la question, où les bibliothèques C ++ peuvent être facilement exportées avec extern "C".
DeadMG
12
@jhominal: C'est beaucoup mieux que de l'écrire en C, où vous devez définir une interface C et l'implémenter également en C, alors qu'en C ++, vous pouvez définir une interface C sans avoir à l'implémenter. il en C Quel que soit le langage que vous implémentez, vous devez toujours définir une interface C, ce qui est bien sûr vrai en C ++ comme en C ou dans tout autre langage pouvant exposer les liaisons C.
DeadMG
9
Serait-il possible d’ajouter une clause de non-responsabilité au lien menant à cette transmission de la FQA?
Martin Ba
2
@ DocBrown: Il me semble que la question porte sur les liaisons en langage C par opposition à celles en langage C ++.
Mason Wheeler
32

Si vous essayez de communiquer avec un locuteur d'une autre langue, le 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, de sorte que d'autres langages peuvent facilement les implémenter suffisamment pour appeler des fonctions C. Pour des raisons historiques, de nombreux autres langages sont implémentés en C, ce qui facilite encore davantage l’appel de fonctions C.

C ++ ajoute pas mal de choses - des classes, avec l'héritage, des vtables et des modificateurs d'accès; les exceptions, avec décompression de la pile et modification du flux de contrôle; modèles. Tout cela rend plus difficile l’utilisation des liaisons C ++ par d’autres langages: au mieux, il faut implémenter davantage de code "collant" ou interopérabilité, et au pire, les concepts ne sont pas traduits directement (en raison de différences dans les modèles de classe, la gestion des exceptions, etc.). Pour les modèles en particulier, leur simple utilisation (leur instanciation) nécessite généralement une étape de compilation avec un compilateur C ++, ce qui complique considérablement 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 ++ vers un autre langage:

  • Les liaisons C ++ peuvent être aussi compatibles que C si vous êtes prêt à travailler dessus. Comme @DeadMG le fait remarquer, C ++ prend en charge extern "C", de sorte que vous pouvez 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 exposer aucune fonctionnalité spécifique à C ++) .
  • Une autre objection commune aux liaisons de langage C ++ est le manque de stabilité ABI pour C ++, mais cela aussi est surestimé; Les ABI C ++ sont moins normalisés que les ABI C, mais il existe des normes et des normes de facto (l’ABI Itanium C ++, qui est également utilisé sur OS X ; la norme de facto de GCC pour Linux). Windows est pire, mais même sous Windows, rester dans une version de Visual C ++ devrait fonctionner correctement.
Josh Kelley
la source
1
L’autre problème avec la liaison d’une bibliothèque C ++ à une autre langue est que l’autre langue peut nécessiter l’implémentation de liaisons en C. Ou, pour les langues qui ont quelque chose comme P (Invite) peut ne fournir aucun outil pour utiliser l’ABI C ++.
Random832
6
@ Random832: Ce qui est complètement hors de propos lorsque le côté C ++ peut simplement offrir l'interface C. Il n'est pas nécessaire d'implémenter la liaison en C pour offrir une liaison en C.
DeadMG
21

C est l’une des langues les plus anciennes qui existe encore. Son ABI est simple et pratiquement tous les systèmes d’exploitation encore utilisés aujourd’hui y ont été écrits . Certains de ces systèmes d’exploitation peuvent avoir ajouté des éléments, par exemple en C # / .NET ou autre, mais 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 existants avaient besoin d'un moyen d'interface avec les bibliothèques C de toute façon . Perl, Java, C ++, ils fournissent tous nativement des moyens de "parler C", car ils devaient le faire s'ils ne voulaient pas réinventer chaque roue.

Cela fait de C le latin des langages de programmation. (Combien d'années d'internet avant cette métaphore doit être "l'anglais des langues de progamming"?)


Lorsque vous écrivez votre bibliothèque en C, vous bénéficiez d’une interface gratuite (évidemment). Si vous écrivez votre bibliothèque en C ++, vous pouvez obtenir des liaisons en C, via des extern "C"déclarations comme vous l'avez mentionné.

Cependant , vous pouvez obtenir ces liaisons que pour des fonctionnalités qui peuvent être exprimées en C .

Donc, votre API de bibliothèque ne peut pas utiliser ...

  • des modèles,
  • Des classes,
  • exceptions,
  • toute fonction prenant ou retournant des objets.

Un exemple simple, vous auriez besoin que vos fonctions exportées prennent et renvoient arrays ( []) à la place de std::vector(ou std::stringd'ailleurs).

Ainsi, non seulement vous ne seriez pas en mesure de fournir les avantages de C ++ aux clients de votre bibliothèque, mais vous devrez également déployer des efforts supplémentaires pour "traduire" votre API de bibliothèque de C ++ en "compatible C" ( extern "C").

C’est pourquoi on pourrait faire valoir que C est le meilleur choix pour la mise en place d’une bibliothèque. Personnellement, je pense que les avantages du C ++ l'emportent toujours sur les efforts nécessaires pour une extern "C"API, mais ce n'est que moi.

DevSolar
la source
Windows semble essayer de se baser sur .NET, Android est basé sur Java (le détail de la mise en œuvre de certaines API est également C ) et iOS / OSX est basé sur Objective-C.
user253751
1
L'anglais est déjà la langue dominante dans le monde de la programmation. Plus dominant que dans d'autres professions.
Siyuan Ren
3
@immibis: Windows, Linux / Android et BSD / OSX sont tous des noyaux écrits en C, avec des interfaces écrites en (et pour) C. Quoiqu'il en soit construit en plus, Java a besoin de JNI, Perl a besoin d'appels C,. NET a besoin d'appels C, Python a besoin d'appels C, Objective-C a besoin d'appels C Aucun de ceux-ci n'a besoin d' appels C ++, ce que j'essayais de dire.
DevSolar
@DevSolar Beaucoup de choses d'Android sont écrites en Java et n'utilisent pas JNI (vous pouvez l'utiliser "à l'envers" pour appeler du code Java à partir de C, mais cela ne fait que confirmer qu'il s'agit de Java en mode natif). Aucune expérience avec iOS / OSX mais j'entends dire que ce sont les mêmes avec Objective-C.
user253751
3
@immibis: Mais vous faites connaître la différence entre un noyau de système d' exploitation et son espace utilisateur, non? Je doute sérieusement qu'un espace utilisateur principalement Java fasse d'Android moins un noyau Linux avec des appels système de style C que le noyau Linux exécuté sur mon bureau. Je doute également qu'ils utilisent Java dans le noyau ou dans le middleware. En fait, je sais qu'ils utilisent C ici. C'est le problème de la poule et de l'œuf, exactement l'inverse. Cela a déjà été fait en C et il est donc beaucoup plus facile de le faire encore en C.
DevSolar
6

En laissant de côté les détails déjà fournis par d'autres réponses:

La raison pour laquelle tant de langues fournissent une liaison C est que tous les systèmes d'exploitation Windows et * exposent la plupart de leurs API de système d'exploitation via une interface C. Donc, l'implémentation du langage doit déjà s'interfacer avec C pour pouvoir fonctionner sur les principaux Oses. Par conséquent, il est simple de proposer également une communication directe avec toute interface C à partir du langage lui-même.

Martin Ba
la source
5

Il n'y a pas de raison. Si la sémantique que vous essayez d'exprimer est fondamentalement compatible avec le C et ne ressemble en rien à des modèles, il n'y a aucune raison de simplifier la liaison si l'implémentation est écrite en C. En fait, c'est à peu près par définition qu'une interface C peut être rempli par toute implémentation pouvant respecter le contrat binaire, y compris une implémentation dans une autre langue. Il existe des langages autres que C ++ pouvant implémenter des contrats binaires C pouvant fonctionner de cette manière.

Cela revient vraiment à des gens qui ne veulent pas apprendre de nouvelles langues ou des idées qui ont une sémantique ou des fonctionnalités utiles qui tentent désespérément de trouver une raison quelconque de rester à l’époque des dinosaures.

DeadMG
la source
4
Je pense que vous avez raison et que les électeurs ont mal compris la question, mais en réalité, votre réponse manque pour mettre en évidence ce malentendu potentiel: la question ne concerne pas "une bibliothèque avec une interface C" ou "une bibliothèque avec une interface C ++", il s'agit de "une bibliothèque entièrement écrite en C" vs "une bibliothèque avec une interface C écrite en C ++".
Doc Brown
@Snowman: Avoir des liaisons C ++ problématiques n'a absolument rien à voir avec un problème d'affichage des liaisons C.
DeadMG
2
Vous allez donc choisir un langage qui possède une sémantique et des fonctionnalités utiles, puis vous forcer à les traduire en interface C? Bien que les classes et les modèles puissent être évités (mais vous demandez pourquoi vous utilisez C ++ en premier lieu), chaque fonction avec la liaison C doit capturer les exceptions au lieu de les laisser s'échapper dans le code C. Sans parler du fait que quiconque utilisant votre bibliothèque compatible C doit maintenant gérer C ++ et ses conflits ABI et incompatibilités de bibliothèque, en plus des conflits ABI et des incompatibilités de bibliothèque du substrat C.
prosfilaes
2
@prosfilaes: Il est simple de convertir les exceptions en codes de retour. Vous n'avez pas besoin d'éviter d'utiliser des classes car celles-ci peuvent facilement être intégrées dans une API C et vous n'avez pas besoin d'éviter d'utiliser des modèles dans votre implémentation. Et vos utilisateurs n'ont pas à se soucier des conflits C ++ ABI à moins qu'ils ne construisent à partir des sources. Dans ce cas, vous devez gérer le langage source, peu importe la raison.
DeadMG
4
J'ai voté négativement non pas parce qu'il ne faut pas nécessairement écrire une bibliothèque avec une API C en C ++, mais parce qu'il y a de bonnes raisons d'utiliser C en plus d'être un dinosaure. Si vous écrivez pour une API en langage X, que ce soit C, FORTRAN, COBOL, BLISS ou Java, il sera toujours plus simple, plus facile et plus correct d'écrire dans ce langage que d'écrire dans un langage plus sophistiqué. , langage plus amusant et interface les deux.
prosfilaes
2

L'interface avec une autre langue comporte deux axes principaux:

  • les concepts que l'interface peut véhiculer: juste des valeurs? références? génériques?
  • comment l'interface est implémentée dans les "binaires" (appelés ABI)

C a un avantage sur C ++ sur ces deux fronts:

  • C n'a que des concepts simples pour la plupart, qui apparaissent dans la plupart des langues 1
  • L'ABI de binaires C est décidé par l'OS 2

Maintenant, pourquoi la plupart des langues ont-elles un ensemble de concepts similaire à celui de C? Cela peut être dû au fait qu'il est "simple" ou "préexistant". cela n'a pas d'importance cependant, le fait est qu'ils le font.

Au contraire, le C ++ a des concepts complexes et l’ABI est décidé par chaque compilateur (bien que beaucoup adhèrent à l’ABI d’Itanimum, sauf sous Windows ...). Herb Sutter a en fait proposé de faire en sorte que les systèmes d’exploitation corrigent une ABI C ++ (système par système d’exploitation) afin de résoudre partiellement ce problème. En outre, il convient de noter qu’un FFI C ++ est possible, D le tente 3 .

1 Sauf variadics ( ...), ce ne sont pas simples

2 C a-t-il un ABI standard?

3 Interfaçage de D avec du code C ++ hérité

Matthieu M.
la source
0

Fondamentalement, il s’agit de la normalisation ABI. Bien que ni C, ni C ++ ne disposent d'une ABI normalisée que d'autres langages peuvent utiliser pour faire l'interface entre les binaires écrits, le C est devenu un standard de facto, tout le monde le sait et tout le monde peut utiliser les mêmes règles simples que le langage a pour types et appels de fonction.

C ++ pourrait avoir une ABI standard, mais Stroustrup a déclaré qu'il n'en voyait pas la nécessité. Il dit également qu'il serait difficile d'obtenir un consensus des rédacteurs de compilateurs (bien que je doute que le comité de standard C ++ émette une ABI similaire à celles existantes et que les rédacteurs de compilateurs modifient simplement la version suivante de leurs compilateurs, qui sont parfois incompatibles avec les fichiers binaires. de toute façon, construit avec d’anciennes versions de leurs compilateurs - je me souviens de la recompilation de quelques bibliothèques avec un nouveau compilateur Sun et de la conclusion qu’elles ne fonctionnaient pas avec les anciennes)

Vous remarquerez que certaines entreprises ont commencé à utiliser une ABI standard. Microsoft a démarré ce processus avec COM dans les années 90 et l'a aujourd'hui affiné dans ABI WinRT (à ne pas confondre avec l'autre WinRT qui fait référence à type de table) qui permet aux programmes écrits en C # de communiquer avec des bibliothèques écrites en C ou C ++ (c’est-à-dire que la couche de système d’exploitation propre à Microsoft est écrite en C ++, exposée à l’aide de WinRT et consommée par les applications C # lorsqu’elles appellent une routine d’exécution OS)

Personne ne peut faire grand chose à moins qu'un organisme de normalisation n'intervienne et ne corrige cette situation. Microsoft en voit évidemment la valeur et a pris des mesures pour la résoudre pour leur plate-forme.

Donc, la réponse est vraiment que C ne fournit pas de liens de langage. Il arrive que personne ne les ait écoutés et les consomme malgré tout.

gbjbaanb
la source
-2

Toutes les réponses ne répondent pas au vrai problème: la compilation en C ++ introduit le "changement de nom", ainsi les fichiers binaires sont incompatibles avec les appels de fonctions "simples".

Tout ce que ABI contient n’est rien de plus qu’une tentative de standardisation.

En général, il n'est pas garanti que vous puissiez interconnecter des fonctions compilées avec différents compilateurs, même si vous vous en tenez à du C ++ standard. Autrefois, il était certain qu’ils étaient incompatibles, mais de nos jours, la normalisation fait son chemin;)

OTOH C a été conçu précisément pour être un "assemblage de haut niveau" et permettre toutes sortes d'interfaces faciles. Cela ne devrait pas surprendre que cela convienne mieux aux goûts multilingues.

Note latérale: le compilateur C ++ original (cfront) a en fait produit une source C qui devait être compilée, exactement comme gcc produisant Assembly "sous le capot".

ZioByte
la source