Компилируемость vs Интерпретируемость
Contents
Компилируемость vs
Интерпретируемость#
Всем известно, что python
является интерпретируемым языком программирования, а C/C++
— компилируемым. Снизу приводятся определения из Wikipedia (1 и 2):
Компилятор — программа, переводящая текст, написанный на языке программирования, в набор машинных кодов.
Интерпретация — построчный анализ, обработка и выполнение исходного кода программы или запроса.
Однако, если пытаться углубиться и провести черту между интерпретируемыми и компилируемыми языками программирования, то оказывается, что не всё так просто. Например, существует интерпретатор для C++
cling, а некоторые интерпретаторы python
(например, PyPy) и библиотеки для python
(например, numba) осуществляют JIT-компиляцию исходного кода python
в машинный код.
Тем не менее стандартный режим работы с C/C++
включает в себя этап компиляции, а наиболее распространенный стандартный интерпретатор CPython
для python
не поддерживает JIT
-компиляцию. Поэтому, для того чтобы обрисовать разницу между компилируемостью и интерпретируемостью, воспользуемся этими языками в качестве примеров.
Компилятор C/С++
#
Цель компилятора — преобразовать текст программы на языке программирования высокого уровня (C/C++
в данном случае) и в машинный код, который может быть исполнен целевой машинной непосредственно. Большинство современных компиляторов (например, gcc
) состоят из трех этапов в соответствии с следующей схемой.
Первая часть (front end) просматривает файлы исходного кода на высокоуровневом языке программирования (например, файлы
.cpp
), и в первую очередь осуществляет проверки: корректность синтаксиса, согласованность типов (C/C++
статически типизированный язык) и т.п. Если обнаруживается ошибка, то генерируется ошибка компиляции. Если ошибок нет, то результатом работы первого блока является внутреннее (промежуточное) представление программы, которые абстрагировано от исходного высокоуровневого языка.Вторая часть (middle end) принимает на вход это промежуточное представление, анализирует его и оптимизирует из соображений логики программы. Например, если какая-то ветвь программы недостижима, то она может быть выкинута, или, например, если компилятор обнаруживает способ переорганизовать вычисления, гарантирующий одновременно неизменный результат и меньшее время исполнения, то он может его применить в зависимости от настроек компиллятора. Однако, важно понимать, что на этом этапе ещё не учитывается информация об архитектуре целевой машины, и уже не учитывается информация об особенностях исходного языка программирования.
Третья часть (back end) принимает на вход оптимизированное промежуточное представление и транслирует его в машинный код для конкретной машины, попутно производя оптимизации, специфичные для архитектуры этой машины.
Такой трёх этапный процесс компиляции позволяет использовать один и тот же middle end для разных языков программирования и архитектур процессоров, меняя front end и back end.
Интерпретатор python
#
Уже упоминалось, что существует несколько разных интерпретаторов для python
, однако CPython
является самым популярным их них с большим заделом. CPython
— интерпретатор для python
, написанный на языке C
. Под установкой python
чаще всего имеют в виду установку интерпретатора CPython
.
CPython
— программа, которая принимает на вход файл с исходным кодом на python
и интерпретирует его по строкам сверху вниз. В процессе интерпретации тоже осуществляется трансляция исходного кода в более низкоуровневую форму, называемою байт-кодом. Байт-код представляет собой последовательность инструкций для виртуальной машинной python
, которая входит в состав интерпретатора. Виртуальная машина python
поддерживает более широкий набор инструкций, чем центральный процессор, и байт-код намеренно является гораздо более абстрактным, чем машинный код. Всё это с одной стороны заметно снижает возможности оптимизации, а с другой стороны обеспечивает более гибкую и динамическую природу языка.
Интерпретатор vs.
компилятор#
Требования к наличию транслятора:
компилятор требуется только на этапе компиляции программы. Когда программа скомпилирована, она может полноценно функционировать без наличия самого компилятора.
интерпретатор требуется при каждом запуске программы. Без интерпретатора запустить программу не удастся.
Возможность оптимизации:
Так как компилятор анализирует весь исходный код программы целиком, то он может оценить сценарии её работы и сгенерировать эффективный машинный код.
Так как интерпретатор видит код программы кусками, то он не может оценить возможные сценарии её работы и возможности оптимизации сводятся к минимуму.
Интерактивность:
Так как компилятор требует весь исходный код программы целиком, то возможности интерактивного взаимодействия сильно ограничены.
Так как интерпретатор обрабатывает исходный код кусками, то открываются возможности к интерактивной подаче новых команд на лету.
Кроссплатформенность:
компилятор генерирует машинный код, который оптимизируется с учетом особенностей операционной системы и архитектуры целевой платформы. В связи с этим требуется отдельная компиляция исходного кода, чтобы сгенерировать машинный код под машину с отличной архитектурой.
Исходный код на
python
запускается внутри виртуальной машиныpython
(интерпретатора), которая изначально компилируется для работы на определенной платформе. За счет этого в подавляющем большинстве случаев программист может абстрагироваться от особенностей операционной системы и архитектуры целевой платформы.