Помимо машинного кода, не существует языка программирования, который выполнялся бы непосредственно на оборудовании, в том смысле, что вы не можете передать его в виде буквального исходного текста. Все реальные реализации должны переводить исходную программу на язык «машины».
Для некоторых реализаций он переводится статически. Мы обычно называем эти реализации "скомпилированными". Для других это переводится в некоторую промежуточную форму, которая затем переводится динамически по мере запуска программы. Мы обычно называем эти реализации "интерпретированными". Между ними существует множество возможностей, и даже многие современные процессоры выполняют динамическую трансляцию как часть своего исполнительного ядра.
Даже когда ваша программа статически компилируется задолго до ее выполнения, если вы не пишете микропрограмму, редко, когда скомпилированный код запускается прямо на голом железе, и ничто его не поддерживает. Операционная система предоставляет виртуальную машину для программ пользовательского пространства, часто обеспечивая такие функции, как иллюзия, что у вас есть центральный процессор для себя. Иллюзия плоского пространства памяти, которое может быть больше, чем физическое ОЗУ, подключенное к машине, даже называется «виртуальной памятью».
Кроме того, даже когда вы программируете на C, существует виртуальная машина C! Это традиционно упоминается как "среда выполнения C", или CRT для краткости.
Поскольку C в основном переводится непосредственно в ассемблерный / машинный код задолго до этого (на некоторых платформах также может существовать некоторый многопоточный код , который можно считать частью виртуальной машины), виртуальная машина обычно должна обрабатывать только запуск неисправность.
Запуск обычно включает в себя настройку стека и кучи; операционная система редко предоставляет их вам, и задача языка программирования - предоставлять их программисту. На некоторых платформах может происходить некоторая инициализация обработки сигналов, настройка «основного» потока в многопоточной среде, запуск глобальных конструкторов на случай, если программа связана с кодом C ++, обработка динамически связанных библиотек или может потребоваться некоторая обработка для установки argc / argv и envp. Наконец, CRT передает управление главному.
Что касается выключения, многие операционные системы могут убить процесс нечистым образом, поэтому выключение не требует особых усилий. Главное - это обработать вызовы atexit () для случая, когда программа завершает работу чисто.