Mis à part le code machine, il n'existe aucun langage de programmation qui s'exécute directement sur le matériel, dans le sens où vous ne pouvez pas lui fournir le texte source littéral. Toutes les implémentations réelles doivent traduire le programme source dans le langage de la "machine".
Pour certaines implémentations, il est traduit statiquement. Nous appelons généralement ces implémentations "compilées". Pour d'autres, il est traduit sous une forme intermédiaire, qui est ensuite traduite dynamiquement lors de l'exécution du programme. Nous appelons généralement ces implémentations "interprétées". Il existe un continuum de possibilités entre celles-ci, et même de nombreux processeurs modernes font la traduction dynamique dans le cadre de son cœur d'exécution.
Même lorsque votre programme est compilé statiquement bien avant son exécution, à moins que vous n'écriviez un micrologiciel, il est rare que le code compilé s'exécute directement sur le métal nu sans rien le prendre en charge. Le système d'exploitation fournit une machine virtuelle pour les programmes de l'espace utilisateur, offrant souvent des fonctionnalités telles que l'illusion que vous avez un processeur pour vous tout seul. L'illusion d'un espace mémoire plat qui pourrait être plus grand que la RAM physique attachée à la machine est même appelée «mémoire virtuelle».
En plus de cela, même lorsque vous programmez en C, il y a une machine virtuelle C! Il est traditionnellement appelé "le runtime C", ou CRT pour faire court.
Étant donné que C est principalement traduit directement en code assembleur / machine bien à l'avance (sur certaines plates-formes, il peut également y avoir du code threadé et qui peut être considéré comme faisant partie de la machine virtuelle), la machine virtuelle ne doit généralement gérer que le démarrage et fermer.
Le démarrage implique généralement la configuration de la pile et du tas; le système d'exploitation vous les fournit rarement, et c'est le travail du langage de programmation de les fournir au programmeur. Sur certaines plates-formes, il peut y avoir une initialisation de la gestion du signal, la configuration du thread "principal" dans un environnement multi-thread, l'exécution de constructeurs globaux au cas où le programme a été lié au code C ++, la gestion de bibliothèques liées dynamiquement, ou là un traitement peut être nécessaire pour configurer argc / argv et envp. Enfin, CRT transfère le contrôle au principal.
En ce qui concerne l'arrêt, de nombreux systèmes d'exploitation peuvent tuer un processus de manière impure, donc l'arrêt n'a pas besoin de faire grand-chose. L'essentiel est de traiter les appels atexit () dans le cas où le programme se ferme correctement.