J'ai récemment lu le livre du dragon sur la conception du compilateur. Il mentionne que le compilateur a la génération de code intermédiaire comme l'une de ses phases qui produit un code indépendant de la machine. Alors pourquoi C n'a-t-il pas été développé comme un langage indépendant de la plate-forme comme java?

1
Curiosity101 24 janv. 2017 à 20:23

5 réponses

Meilleure réponse

Ce que le livre du dragon décrit est le processus suivant:

  1. Compilez le code source dans un format de code d'octet intermédiaire indépendant de la machine
  2. Effectuer des optimisations et des analyses sur cet IR
  3. Traduire l'IR en code machine réel de la plate-forme cible

L'avantage de ceci est que si vous souhaitez prendre en charge des systèmes supplémentaires, il vous suffit d'ajouter un nouveau générateur de code pour l'étape 3 sans avoir à toucher aux étapes 1 et 2.

Tous les compilateurs C courants fonctionnent de cette façon. Donc, si votre question est "Pourquoi les compilateurs C ne font-ils pas ce que le Dragon Book décrit?", La réponse est: "Ils font".

Maintenant, vous avez mentionné Java. Ce qu'un compilateur Java fait est le suivant:

  1. Compilez le code Java en code octet Java. En ce qui concerne le compilateur Java, ce n'est pas un format intermédiaire, mais le véritable langage cible.
  2. La fin

Maintenant, pour exécuter ce code d'octet, vous avez besoin d'une JVM, qui interprète le code d'octet et / ou le compile par JIT. Les optimisations et analyses se produisent généralement lors de la compilation JIT. Ce n'est pas le processus décrit dans le Dragon Book.

Du point de vue des développeurs de langage, cela ne change pas beaucoup l'effort de prise en charge d'un nouveau système cible. Vous n'avez plus à changer le compilateur, mais à la place vous devez changer la JVM: au lieu d'avoir à ajouter un nouveau backend au compilateur javac, vous ajoutez à la place un nouveau backend au compilateur JIT. L'effort reste fondamentalement le même.

La principale différence concerne les programmeurs Java: au lieu de compiler le programme pour chaque plate-forme cible et de distribuer des packages pour chaque plate-forme, vous pouvez maintenant compiler le code une fois et donner le package résultant à tout le monde. Maintenant, les personnes exécutant votre code doivent installer une JVM pour pouvoir utiliser le package, donc vous avez essentiellement déplacé l'effort du programmeur vers l'utilisateur final, mais l'installation d'une JVM est quelque chose que vous ne devez faire qu'une seule fois (pas pour chaque Java programme que vous souhaitez exécuter).

Donc au lieu de "écrire une fois, compiler partout", vous avez maintenant "compiler une fois, exécuter partout".

Alors pourquoi C n'a-t-il pas fait la même chose que Java? Performance. L'interprétation du code d'octet est lente (par rapport à l'exécution du code compilé) et la compilation JIT entraîne une augmentation du temps de démarrage.

10
sepp2k 11 août 2018 à 11:01

En plus de laisser un certain nombre de choses définies par l'implémentation (en pratique, cela est largement défini par la plate-forme / ABI, mais à proprement parler ne doit pas l'être), C est principalement une plate-forme indépendante langue . En effet, il existe des implémentations de C (comme emscripten) qui produisent une sortie sous une forme qui peut s'exécuter sur n'importe quelle plate-forme de machine avec le bon environnement d'exécution. Si un logiciel écrit en C émet des hypothèses sur les aspects définis par l'implémentation (ou pire, non définis) du langage, il peut alors ne pas fonctionner sur certaines implémentations / machines, mais la cause est souvent plus une question d'API / d'environnement / de bibliothèque hypothèses (comme supposer POSIX, ou Windows, ou glibcismes) que de faire des hypothèses non transférables sur le langage lui-même.

0
R.. GitHub STOP HELPING ICE 24 janv. 2017 à 18:07

C a été initialement conçu pour un cas d'utilisation particulier, qui impliquait une machine spécifique. Bien qu'il soit vaguement basé sur le langage BCPL, qui a été implémenté au moyen d'une machine virtuelle indépendante de la plate-forme, l'objectif pour C était de pouvoir écrire du code de bas niveau, tel qu'un système d'exploitation, ce qui signifiait qu'il devait pouvoir profiter des fonctionnalités spécifiques de la machine cible, notamment sa capacité à adresser directement des octets individuels. En revanche, l'architecture sous-jacente de la BCPL est résolument motivée.

Le fait que Bell Labs ait pu réimplémenter rapidement le système d'exploitation Unix dans leur nouveau langage (C) a certainement contribué à sa popularité. (Du moins, c'est pourquoi je l'ai appris au départ.) Pour permettre une diffusion plus large du langage, une version du compilateur a été écrite de plus près en suivant l'architecture décrite dans le Dragon Book, avec une génération initiale de code de machine virtuelle qui est puis utilisé pour produire du code pour une machine cible. Ce compilateur portable C a été pendant de nombreuses années une implémentation de référence et continue d'être disponible.

D'autres langages contemporains de C, notamment Pascal, ont également utilisé la tactique consistant à cibler une machine virtuelle indépendante de la plate-forme, et il était autrefois courant de se référer au code de la machine virtuelle comme "P-Code" parce que c'est ce que le projet Pascal de Niklaus Wirth appelait leur architecture cible.

Bien que GCC n'utilise pas de machine virtuelle en tant que telle, il commence par générer une représentation interne indépendante de la machine de niveau liw, simplifiant la tâche de portage du compilateur vers de nouvelles architectures. Et bien sûr, le compilateur Clang produit du code LLVM (machine virtuelle de bas niveau), qui peut être transpilé en divers codes machine concrets, ou interprété directement.

2
rici 24 janv. 2017 à 18:51

C a été conçu et écrit à l'origine comme un langage "Write-Once, Compile-Anywhere", qui était aussi proche que possible à l'époque d'un langage universel.

Les processeurs et les architectures étaient si radicalement différents, et les ressources étaient si petites que l'idée d'une machine virtuelle universelle (comme Java l'a fait) était tout simplement impossible.

L'idée qu'une seule base de code puisse être exécutée via un compilateur, puis que vous ayez le même logiciel sur n'importe quelle plate-forme cible était assez incroyable.

1
abelenky 24 janv. 2017 à 18:15

La réponse courte: parce que ce n'était pas faisable à ce moment-là.

La réponse longue: la plate-forme Java est un langage + machine virtuelle, le code Java se compile en quelque chose appelé ByteCode, puis la machine virtuelle peut prendre ce code d'octet (il est similaire au langage d'assemblage) et le traduit en la commande appropriée au moment de l'exécution, c'est-à-dire l'instruction machine qui sera comprise par la machine locale.

Chaque architecture a son propre jeu d'instructions, ce qui signifie qu'une architecture ARM ne pourra pas comprendre le code compilé pour l'architecture x86 par exemple.

En C, le code c est compilé directement en instructions machine, ces instructions sont ensuite exécutées par la machine locale. pour obtenir un comportement comme Java, vous aurez besoin d'une sorte d'interpréteur qui lit C et le traduit en code machine au moment de l'exécution, ce n'est pas une tâche bon marché et c'était beaucoup trop pour les ordinateurs de l'époque (c a été inventé en 1972 ) bien sûr, une autre façon de l'implémenter est de demander à l'utilisateur de compiler votre programme avant de l'utiliser, ce qui pourrait être bien mais impliquera probablement de rendre votre code source visible pour le client, ce qui n'est pas souhaité. j'espère que cela clarifie un peu les choses.

1
monkeyStix 25 janv. 2017 à 06:17