Além do código da máquina, não existe uma linguagem de programação que seja executada diretamente no hardware, no sentido de que você não pode alimentá-lo com o texto fonte literal. Todas as implementações reais devem traduzir o programa de origem no idioma da "máquina".
Para algumas implementações, é traduzido estaticamente. Geralmente chamamos essas implementações de "compiladas". Para outros, é traduzido para alguma forma intermediária, que é traduzida dinamicamente à medida que o programa é executado. Geralmente chamamos essas implementações de "interpretadas". Há um continuum de possibilidades entre elas, e até muitas CPUs modernas fazem a tradução dinâmica como parte de seu núcleo de execução.
Mesmo quando seu programa é estaticamente compilado muito antes da execução, a menos que você esteja escrevendo firmware, é raro que o código compilado seja executado diretamente no bare metal sem nada que o suporte. O sistema operacional fornece uma máquina virtual para programas de espaço do usuário, geralmente fornecendo recursos como a ilusão de que você tem uma CPU só para si. A ilusão de um espaço de memória plano que pode ser maior que a RAM física conectada à máquina é chamada de "memória virtual".
Além disso, mesmo quando você está programando em C, há uma máquina virtual em C! É tradicionalmente chamado de "o tempo de execução C", ou CRT, para abreviar.
Como C é traduzido principalmente diretamente para código de montagem / máquina com bastante antecedência (em algumas plataformas, também pode haver algum código encadeado e que pode ser considerado parte da máquina virtual), a máquina virtual geralmente só precisa lidar com inicialização e desligar.
A inicialização normalmente envolve a configuração da pilha e da pilha; o sistema operacional raramente os fornece e é tarefa da linguagem de programação fornecê-los ao programador. Em algumas plataformas, pode haver alguma inicialização do tratamento de sinais, configurando o encadeamento "principal" em um ambiente com vários encadeamentos, executando construtores globais com a possibilidade de o programa ter sido vinculado ao código C ++, manipulando bibliotecas vinculadas dinamicamente ou existindo pode haver algum processamento necessário para configurar argc / argv e envp. Finalmente, o CRT transfere o controle para o main.
Quanto ao desligamento, muitos sistemas operacionais podem matar um processo de maneira impura, portanto o desligamento não precisa fazer muito. O principal é processar chamadas atexit () para o caso em que o programa sai corretamente.