Содержание

Компиляция (программирование) — это… Что такое Компиляция (программирование)?

Компиля́тор —

  • Программа, предназначенная для трансляции высокоуровневого языка в абсолютный код или, иногда, в язык ассемблера. Входной информацией для компилятора (исходный код) является описание алгоритма или программа на проблемно-ориентированном языке, а на выходе компилятора — эквивалентное описание алгоритма на машинно-ориентированном языке (объектный код).[5]

Компиляция

  • Трансляция программы на язык, близкий к машинному.[3][2]
  • Трансляция программы, составленной на исходном языке, в объектный модуль. Осуществляется компилятором.[2]

Компилировать — проводить трансляцию машинной программы с проблемно-ориентированного языка на машинно-ориентированный язык.[3]

Виды компиляторов

[2]
  • Векторизующий. Транслирует исходный код в машинный код компьютеров, оснащённых векторным процессором.
  • Гибкий. Составлен по модульному принципу, управляется таблицами и запрограммирован на языке высокого уровня или реализован с помощью компилятора компиляторов.
  • Диалоговый. См.: диалоговый транслятор.
  • Инкрементальный. Повторно транслирует фрагменты программы и дополнения к ней без перекомпиляции всей программы.
  • Интерпретирующий (пошаговый). Последовательно выполняет независимую компиляцию каждого отдельного оператора (команды) исходной программы.
  • Компилятор компиляторов. Транслятор, воспринимающий формальное описание языка программирования и генерирующий компилятор для этого языка.
  • Отладочный. Устраняет отдельные виды синтаксических ошибок.
  • Резидентный. Постоянно находится в основной памяти и доступен для повторного использования многими задачами.
  • Самокомпилируемый. Написан на том же языке, с которого осуществляется трансляция.
  • Универсальный. Основан на формальном описании синтаксиса и семантики входного языка. Составными частями такого компилятора являются: ядро, синтаксический и семантический загрузчики.

Виды компиляции

[2]
  • Пакетная. Компиляция нескольких исходных модулей в одном пункте задания.
  • Построчная. То же, что и интерпретация.
  • Условная. Компиляция, при которой транслируемый текст зависит от условий, заданных в исходной программе. Так, в зависимости от значения некоторой константы, можно включать или выключать трансляцию части текста программы.

Основы

Большинство компиляторов переводит программу с некоторого высокоуровневого языка программирования в машинный код, который может быть непосредственно выполнен центральным процессором. Как правило, этот код также ориентирован на исполнение в среде конкретной операционной системы, поскольку использует предоставляемые ею возможности (системные вызовы, библиотеки функций). Архитектура (набор программно-аппаратных средств), для которой производится компиляция, называется

целевой машиной.

Некоторые компиляторы (например, низкоуровневом языке. Такой язык — байт-код — также можно считать языком машинных команд, поскольку он подлежит интерпретации виртуальной машиной. Например, для языка Java это JVM (язык виртуальной машины Java), или так называемый байт-код Java (вслед за ним все промежуточные низкоуровневые языки стали называть байт-кодами). Для языков программирования на платформе .NET Framework (C#, Managed C++, Visual Basic .NET и другие) — это MSIL (Microsoft Intermediate Language).

Программа на байт-коде подлежит интерпретации виртуальной машиной, либо ещё одной компиляции уже в машинный код непосредственно перед исполнением. Последнее называется «Just-In-Time компиляция» (MSIL-код компилируется в код целевой машины также JIT-компилятором, а библиотеки .NET Framework компилируются заранее).

Для каждой целевой машины (Apple и т. д.) и каждой операционной системы или семейства операционных систем, работающих на целевой машине, требуется написание своего компилятора. Существуют также так называемые кросс-компиляторы, позволяющие на одной машине и в среде одной ОС получать код, предназначенный для выполнения на другой целевой машине и/или в среде другой ОС. Кроме того, компиляторы могут быть оптимизированы под разные типы процессоров из одного семейства (путём использования специфичных для этих процессоров инструкций). Например, код, скомпилированный под процессоры семейства MMX, SSE2.

Также существуют компиляторы, переводящие программу с языка высокого уровня на язык ассемблера.

Существуют программы, которые решают обратную задачу — перевод программы с низкоуровневого языка на высокоуровневый. Этот процесс называют декомпиляцией, а программы — декомпиляторами. Но поскольку компиляция — это процесс с потерями, точно восстановить исходный код, скажем, на C++, в общем случае невозможно. Более эффективно декомпилируются программы в байт-кодах — например, существует довольно надёжный декомпилятор для Flash. Сходным процессом является дизассемблирование машинного кода в код на языке ассемблера, который всегда выполняется успешно. Связано это с тем, что между кодами машинных команд и командами ассемблера имеется практически однозначное соответствие.

Структура компилятора

Процесс компиляции состоит из следующих этапов:

  1. Лексический анализ. На этом этапе последовательность символов исходного файла преобразуется в последовательность лексем.
  2. Синтаксический (грамматический) анализ. Последовательность лексем преобразуется в дерево разбора.
  3. Семантический анализ. Дерево разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их декларациям, типам, проверка совместимости, определение типов выражений и т. д. Результат обычно называется «промежуточным представлением/кодом», и может быть дополненным деревом разбора, новым деревом, абстрактным набором команд или чем-то ещё, удобным для дальнейшей обработки.
  4. Оптимизация. Выполняется удаление излишних конструкций и упрощение кода с сохранением его смысла. Оптимизация может быть на разных уровнях и этапах — например, над промежуточным кодом или над конечным машинным кодом.
  5. Генерация кода. Из промежуточного представления порождается код на целевом языке.

В конкретных реализациях компиляторов эти этапы могут быть раздельны или совмещены в том или ином виде.

Трансляция и компоновка

Важной исторической особенностью компилятора, отражённой в его названии (англ.

compile — собирать вместе, составлять), являлось то, что он мог производить и компоновку (то есть содержал две части — транслятор и компоновщик). Это связано с тем, что раздельная компиляция и компоновка как отдельная стадия сборки выделились значительно позже появления компиляторов, и многие популярные компиляторы (например, GCC) до сих пор физически объединены со своими компоновщиками. В связи с этим, вместо термина «компилятор» иногда используют термин «транслятор» как его синоним: либо в старой литературе, либо когда хотят подчеркнуть его способность переводить программу в машинный код (и наоборот, используют термин «компилятор» для подчёркивания способности собирать из многих файлов один).

Интересные факты

  • На заре развития компьютеров первые компиляторы (трансляторы) называли «программирующими программами»[6]
    (так как в тот момент программой считался только машинный код, а «программирующая программа» была способна из человеческого текста сделать машинный код, то есть запрограммировать ЭВМ).

Примечания

  1. ГОСТ 19781-83 // Вычислительная техника. Терминология: Справочное пособие. Выпуск 1 / Рецензент канд. техн. наук Ю. П. Селиванов. — М.: Издательство стандартов, 1989. — 168 с. — 55 000 экз. — ISBN 5-7050-0155-X
  2. 1 2 3 4 5 6 7 Першиков В. И., Савинков В. М. Толковый словарь по информатике / Рецензенты: канд. физ.-мат. наук А. С. Марков и д-р физ.-мат. наук И. В. Поттосин. — М.: Финансы и статистика, 1991. — 543 с. — 50 000 экз. — ISBN 5-279-00367-0
  3. 1 2 3 СТ ИСО 2382/7-77 // Вычислительная техника. Терминология. Указ. соч.
  4. Борковский А. Б. Англо-русский словарь по программированию и информатике (с толкованиями). — М.: Русский язык, 1990. — 335 с. — 50 050 (доп.) экз. — ISBN 5-200-01169-3
  5. Толковый словарь по вычислительным системам = Dictionary of Computing / Под ред. В. Иллингуорта и др.: Пер. с англ. А. К. Белоцкого и др.; Под ред. Е. К. Масловского. — М.: Машиностроение, 1990. — 560 с. — 70 000 (доп.) экз. — ISBN 5-217-00617-X (СССР), ISBN 0-19-853913-4 (Великобритания)
  6. Н. А. Криницкий, Г. А. Миронов, Г. Д. Фролов. Программирование / Под ред. М. Р. Шура-Бура. — М.: Государственное издательство физико-математической литературы, 1963.

См. также

Реализации компиляторов

Литература

  • Альфред В. Ахо, Моника С. Лам, Рави Сети, Джеффри Д. Ульман. Компиляторы: принципы, технологии и инструментарий = Compilers: Principles, Techniques, and Tools. — 2-е изд. — М.: Вильямс, 2008. — ISBN 978-5-8459-1349-4
  • Робин Хантер. Основные концепции компиляторов = The Essence of Compilers. — М.: Вильямс, 2002. — С. 256. — ISBN 0-13-727835-7
  • Хантер Р. Проектирование и конструирование компиляторов / Пер. с англ. С. М. Круговой. — М.: Финансы и статистика, 1984. — 232 с.
  • Д. Креншоу. Давайте создадим компилятор!.

Wikimedia Foundation. 2010.

Компиляция (программирование) — это… Что такое Компиляция (программирование)?

Компиля́тор —

  • Программа, предназначенная для трансляции высокоуровневого языка в абсолютный код или, иногда, в язык ассемблера. Входной информацией для компилятора (исходный код) является описание алгоритма или программа на проблемно-ориентированном языке, а на выходе компилятора — эквивалентное описание алгоритма на машинно-ориентированном языке (объектный код).
    [5]

Компиляция

  • Трансляция программы на язык, близкий к машинному.[3][2]
  • Трансляция программы, составленной на исходном языке, в объектный модуль. Осуществляется компилятором.[2]

Компилировать — проводить трансляцию машинной программы с проблемно-ориентированного языка на машинно-ориентированный язык.[3]

Виды компиляторов

[2]
  • Векторизующий. Транслирует исходный код в машинный код компьютеров, оснащённых векторным процессором.
  • Гибкий. Составлен по модульному принципу, управляется таблицами и запрограммирован на языке высокого уровня или реализован с помощью компилятора компиляторов.
  • Диалоговый. См.: диалоговый транслятор.
  • Инкрементальный. Повторно транслирует фрагменты программы и дополнения к ней без перекомпиляции всей программы.
  • Интерпретирующий (пошаговый). Последовательно выполняет независимую компиляцию каждого отдельного оператора (команды) исходной программы.
  • Компилятор компиляторов. Транслятор, воспринимающий формальное описание языка программирования и генерирующий компилятор для этого языка.
  • Отладочный. Устраняет отдельные виды синтаксических ошибок.
  • Резидентный. Постоянно находится в основной памяти и доступен для повторного использования многими задачами.
  • Самокомпилируемый. Написан на том же языке, с которого осуществляется трансляция.
  • Универсальный. Основан на формальном описании синтаксиса и семантики входного языка. Составными частями такого компилятора являются: ядро, синтаксический и семантический загрузчики.

Виды компиляции

[2]
  • Пакетная. Компиляция нескольких исходных модулей в одном пункте задания.
  • Построчная. То же, что и интерпретация.
  • Условная. Компиляция, при которой транслируемый текст зависит от условий, заданных в исходной программе. Так, в зависимости от значения некоторой константы, можно включать или выключать трансляцию части текста программы.

Основы

Большинство компиляторов переводит программу с некоторого высокоуровневого языка программирования в машинный код, который может быть непосредственно выполнен центральным процессором. Как правило, этот код также ориентирован на исполнение в среде конкретной операционной системы, поскольку использует предоставляемые ею возможности (системные вызовы, библиотеки функций). Архитектура (набор программно-аппаратных средств), для которой производится компиляция, называется целевой машиной.

Некоторые компиляторы (например, низкоуровневом языке. Такой язык — байт-код — также можно считать языком машинных команд, поскольку он подлежит интерпретации виртуальной машиной. Например, для языка Java это JVM (язык виртуальной машины Java), или так называемый байт-код Java (вслед за ним все промежуточные низкоуровневые языки стали называть байт-кодами). Для языков программирования на платформе .NET Framework (C#, Managed C++, Visual Basic .NET и другие) — это MSIL (Microsoft Intermediate Language).

Программа на байт-коде подлежит интерпретации виртуальной машиной, либо ещё одной компиляции уже в машинный код непосредственно перед исполнением. Последнее называется «Just-In-Time компиляция» (MSIL-код компилируется в код целевой машины также JIT-компилятором, а библиотеки .NET Framework компилируются заранее).

Для каждой целевой машины (Apple и т. д.) и каждой операционной системы или семейства операционных систем, работающих на целевой машине, требуется написание своего компилятора. Существуют также так называемые кросс-компиляторы, позволяющие на одной машине и в среде одной ОС получать код, предназначенный для выполнения на другой целевой машине и/или в среде другой ОС. Кроме того, компиляторы могут быть оптимизированы под разные типы процессоров из одного семейства (путём использования специфичных для этих процессоров инструкций). Например, код, скомпилированный под процессоры семейства MMX, SSE2.

Также существуют компиляторы, переводящие программу с языка высокого уровня на язык ассемблера.

Существуют программы, которые решают обратную задачу — перевод программы с низкоуровневого языка на высокоуровневый. Этот процесс называют декомпиляцией, а программы — декомпиляторами. Но поскольку компиляция — это процесс с потерями, точно восстановить исходный код, скажем, на C++, в общем случае невозможно. Более эффективно декомпилируются программы в байт-кодах — например, существует довольно надёжный декомпилятор для Flash. Сходным процессом является дизассемблирование машинного кода в код на языке ассемблера, который всегда выполняется успешно. Связано это с тем, что между кодами машинных команд и командами ассемблера имеется практически однозначное соответствие.

Структура компилятора

Процесс компиляции состоит из следующих этапов:

  1. Лексический анализ. На этом этапе последовательность символов исходного файла преобразуется в последовательность лексем.
  2. Синтаксический (грамматический) анализ. Последовательность лексем преобразуется в дерево разбора.
  3. Семантический анализ. Дерево разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их декларациям, типам, проверка совместимости, определение типов выражений и т. д. Результат обычно называется «промежуточным представлением/кодом», и может быть дополненным деревом разбора, новым деревом, абстрактным набором команд или чем-то ещё, удобным для дальнейшей обработки.
  4. Оптимизация. Выполняется удаление излишних конструкций и упрощение кода с сохранением его смысла. Оптимизация может быть на разных уровнях и этапах — например, над промежуточным кодом или над конечным машинным кодом.
  5. Генерация кода. Из промежуточного представления порождается код на целевом языке.

В конкретных реализациях компиляторов эти этапы могут быть раздельны или совмещены в том или ином виде.

Трансляция и компоновка

Важной исторической особенностью компилятора, отражённой в его названии (англ. compile — собирать вместе, составлять), являлось то, что он мог производить и компоновку (то есть содержал две части — транслятор и компоновщик). Это связано с тем, что раздельная компиляция и компоновка как отдельная стадия сборки выделились значительно позже появления компиляторов, и многие популярные компиляторы (например, GCC) до сих пор физически объединены со своими компоновщиками. В связи с этим, вместо термина «компилятор» иногда используют термин «транслятор» как его синоним: либо в старой литературе, либо когда хотят подчеркнуть его способность переводить программу в машинный код (и наоборот, используют термин «компилятор» для подчёркивания способности собирать из многих файлов один).

Интересные факты

  • На заре развития компьютеров первые компиляторы (трансляторы) называли «программирующими программами»[6] (так как в тот момент программой считался только машинный код, а «программирующая программа» была способна из человеческого текста сделать машинный код, то есть запрограммировать ЭВМ).

Примечания

  1. ГОСТ 19781-83 // Вычислительная техника. Терминология: Справочное пособие. Выпуск 1 / Рецензент канд. техн. наук Ю. П. Селиванов. — М.: Издательство стандартов, 1989. — 168 с. — 55 000 экз. — ISBN 5-7050-0155-X
  2. 1 2 3 4 5 6 7 Першиков В. И., Савинков В. М. Толковый словарь по информатике / Рецензенты: канд. физ.-мат. наук А. С. Марков и д-р физ.-мат. наук И. В. Поттосин. — М.: Финансы и статистика, 1991. — 543 с. — 50 000 экз. — ISBN 5-279-00367-0
  3. 1 2 3 СТ ИСО 2382/7-77 // Вычислительная техника. Терминология. Указ. соч.
  4. Борковский А. Б. Англо-русский словарь по программированию и информатике (с толкованиями). — М.: Русский язык, 1990. — 335 с. — 50 050 (доп.) экз. — ISBN 5-200-01169-3
  5. Толковый словарь по вычислительным системам = Dictionary of Computing / Под ред. В. Иллингуорта и др.: Пер. с англ. А. К. Белоцкого и др.; Под ред. Е. К. Масловского. — М.: Машиностроение, 1990. — 560 с. — 70 000 (доп.) экз. — ISBN 5-217-00617-X (СССР), ISBN 0-19-853913-4 (Великобритания)
  6. Н. А. Криницкий, Г. А. Миронов, Г. Д. Фролов. Программирование / Под ред. М. Р. Шура-Бура. — М.: Государственное издательство физико-математической литературы, 1963.

См. также

Реализации компиляторов

Литература

  • Альфред В. Ахо, Моника С. Лам, Рави Сети, Джеффри Д. Ульман. Компиляторы: принципы, технологии и инструментарий = Compilers: Principles, Techniques, and Tools. — 2-е изд. — М.: Вильямс, 2008. — ISBN 978-5-8459-1349-4
  • Робин Хантер. Основные концепции компиляторов = The Essence of Compilers. — М.: Вильямс, 2002. — С. 256. — ISBN 0-13-727835-7
  • Хантер Р. Проектирование и конструирование компиляторов / Пер. с англ. С. М. Круговой. — М.: Финансы и статистика, 1984. — 232 с.
  • Д. Креншоу. Давайте создадим компилятор!.

Wikimedia Foundation. 2010.

Компиляция (программирование) — это… Что такое Компиляция (программирование)?

Компиля́тор —

  • Программа, предназначенная для трансляции высокоуровневого языка в абсолютный код или, иногда, в язык ассемблера. Входной информацией для компилятора (исходный код) является описание алгоритма или программа на проблемно-ориентированном языке, а на выходе компилятора — эквивалентное описание алгоритма на машинно-ориентированном языке (объектный код).[5]

Компиляция

  • Трансляция программы на язык, близкий к машинному.[3][2]
  • Трансляция программы, составленной на исходном языке, в объектный модуль. Осуществляется компилятором.[2]

Компилировать — проводить трансляцию машинной программы с проблемно-ориентированного языка на машинно-ориентированный язык.[3]

Виды компиляторов

[2]
  • Векторизующий. Транслирует исходный код в машинный код компьютеров, оснащённых векторным процессором.
  • Гибкий. Составлен по модульному принципу, управляется таблицами и запрограммирован на языке высокого уровня или реализован с помощью компилятора компиляторов.
  • Диалоговый. См.: диалоговый транслятор.
  • Инкрементальный. Повторно транслирует фрагменты программы и дополнения к ней без перекомпиляции всей программы.
  • Интерпретирующий (пошаговый). Последовательно выполняет независимую компиляцию каждого отдельного оператора (команды) исходной программы.
  • Компилятор компиляторов. Транслятор, воспринимающий формальное описание языка программирования и генерирующий компилятор для этого языка.
  • Отладочный. Устраняет отдельные виды синтаксических ошибок.
  • Резидентный. Постоянно находится в основной памяти и доступен для повторного использования многими задачами.
  • Самокомпилируемый. Написан на том же языке, с которого осуществляется трансляция.
  • Универсальный. Основан на формальном описании синтаксиса и семантики входного языка. Составными частями такого компилятора являются: ядро, синтаксический и семантический загрузчики.

Виды компиляции

[2]
  • Пакетная. Компиляция нескольких исходных модулей в одном пункте задания.
  • Построчная. То же, что и интерпретация.
  • Условная. Компиляция, при которой транслируемый текст зависит от условий, заданных в исходной программе. Так, в зависимости от значения некоторой константы, можно включать или выключать трансляцию части текста программы.

Основы

Большинство компиляторов переводит программу с некоторого высокоуровневого языка программирования в машинный код, который может быть непосредственно выполнен центральным процессором. Как правило, этот код также ориентирован на исполнение в среде конкретной операционной системы, поскольку использует предоставляемые ею возможности (системные вызовы, библиотеки функций). Архитектура (набор программно-аппаратных средств), для которой производится компиляция, называется целевой машиной.

Некоторые компиляторы (например, низкоуровневом языке. Такой язык — байт-код — также можно считать языком машинных команд, поскольку он подлежит интерпретации виртуальной машиной. Например, для языка Java это JVM (язык виртуальной машины Java), или так называемый байт-код Java (вслед за ним все промежуточные низкоуровневые языки стали называть байт-кодами). Для языков программирования на платформе .NET Framework (C#, Managed C++, Visual Basic .NET и другие) — это MSIL (Microsoft Intermediate Language).

Программа на байт-коде подлежит интерпретации виртуальной машиной, либо ещё одной компиляции уже в машинный код непосредственно перед исполнением. Последнее называется «Just-In-Time компиляция» (MSIL-код компилируется в код целевой машины также JIT-компилятором, а библиотеки .NET Framework компилируются заранее).

Для каждой целевой машины (Apple и т. д.) и каждой операционной системы или семейства операционных систем, работающих на целевой машине, требуется написание своего компилятора. Существуют также так называемые кросс-компиляторы, позволяющие на одной машине и в среде одной ОС получать код, предназначенный для выполнения на другой целевой машине и/или в среде другой ОС. Кроме того, компиляторы могут быть оптимизированы под разные типы процессоров из одного семейства (путём использования специфичных для этих процессоров инструкций). Например, код, скомпилированный под процессоры семейства MMX, SSE2.

Также существуют компиляторы, переводящие программу с языка высокого уровня на язык ассемблера.

Существуют программы, которые решают обратную задачу — перевод программы с низкоуровневого языка на высокоуровневый. Этот процесс называют декомпиляцией, а программы — декомпиляторами. Но поскольку компиляция — это процесс с потерями, точно восстановить исходный код, скажем, на C++, в общем случае невозможно. Более эффективно декомпилируются программы в байт-кодах — например, существует довольно надёжный декомпилятор для Flash. Сходным процессом является дизассемблирование машинного кода в код на языке ассемблера, который всегда выполняется успешно. Связано это с тем, что между кодами машинных команд и командами ассемблера имеется практически однозначное соответствие.

Структура компилятора

Процесс компиляции состоит из следующих этапов:

  1. Лексический анализ. На этом этапе последовательность символов исходного файла преобразуется в последовательность лексем.
  2. Синтаксический (грамматический) анализ. Последовательность лексем преобразуется в дерево разбора.
  3. Семантический анализ. Дерево разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их декларациям, типам, проверка совместимости, определение типов выражений и т. д. Результат обычно называется «промежуточным представлением/кодом», и может быть дополненным деревом разбора, новым деревом, абстрактным набором команд или чем-то ещё, удобным для дальнейшей обработки.
  4. Оптимизация. Выполняется удаление излишних конструкций и упрощение кода с сохранением его смысла. Оптимизация может быть на разных уровнях и этапах — например, над промежуточным кодом или над конечным машинным кодом.
  5. Генерация кода. Из промежуточного представления порождается код на целевом языке.

В конкретных реализациях компиляторов эти этапы могут быть раздельны или совмещены в том или ином виде.

Трансляция и компоновка

Важной исторической особенностью компилятора, отражённой в его названии (англ. compile — собирать вместе, составлять), являлось то, что он мог производить и компоновку (то есть содержал две части — транслятор и компоновщик). Это связано с тем, что раздельная компиляция и компоновка как отдельная стадия сборки выделились значительно позже появления компиляторов, и многие популярные компиляторы (например, GCC) до сих пор физически объединены со своими компоновщиками. В связи с этим, вместо термина «компилятор» иногда используют термин «транслятор» как его синоним: либо в старой литературе, либо когда хотят подчеркнуть его способность переводить программу в машинный код (и наоборот, используют термин «компилятор» для подчёркивания способности собирать из многих файлов один).

Интересные факты

  • На заре развития компьютеров первые компиляторы (трансляторы) называли «программирующими программами»[6] (так как в тот момент программой считался только машинный код, а «программирующая программа» была способна из человеческого текста сделать машинный код, то есть запрограммировать ЭВМ).

Примечания

  1. ГОСТ 19781-83 // Вычислительная техника. Терминология: Справочное пособие. Выпуск 1 / Рецензент канд. техн. наук Ю. П. Селиванов. — М.: Издательство стандартов, 1989. — 168 с. — 55 000 экз. — ISBN 5-7050-0155-X
  2. 1 2 3 4 5 6 7 Першиков В. И., Савинков В. М. Толковый словарь по информатике / Рецензенты: канд. физ.-мат. наук А. С. Марков и д-р физ.-мат. наук И. В. Поттосин. — М.: Финансы и статистика, 1991. — 543 с. — 50 000 экз. — ISBN 5-279-00367-0
  3. 1 2 3 СТ ИСО 2382/7-77 // Вычислительная техника. Терминология. Указ. соч.
  4. Борковский А. Б. Англо-русский словарь по программированию и информатике (с толкованиями). — М.: Русский язык, 1990. — 335 с. — 50 050 (доп.) экз. — ISBN 5-200-01169-3
  5. Толковый словарь по вычислительным системам = Dictionary of Computing / Под ред. В. Иллингуорта и др.: Пер. с англ. А. К. Белоцкого и др.; Под ред. Е. К. Масловского. — М.: Машиностроение, 1990. — 560 с. — 70 000 (доп.) экз. — ISBN 5-217-00617-X (СССР), ISBN 0-19-853913-4 (Великобритания)
  6. Н. А. Криницкий, Г. А. Миронов, Г. Д. Фролов. Программирование / Под ред. М. Р. Шура-Бура. — М.: Государственное издательство физико-математической литературы, 1963.

См. также

Реализации компиляторов

Литература

  • Альфред В. Ахо, Моника С. Лам, Рави Сети, Джеффри Д. Ульман. Компиляторы: принципы, технологии и инструментарий = Compilers: Principles, Techniques, and Tools. — 2-е изд. — М.: Вильямс, 2008. — ISBN 978-5-8459-1349-4
  • Робин Хантер. Основные концепции компиляторов = The Essence of Compilers. — М.: Вильямс, 2002. — С. 256. — ISBN 0-13-727835-7
  • Хантер Р. Проектирование и конструирование компиляторов / Пер. с англ. С. М. Круговой. — М.: Финансы и статистика, 1984. — 232 с.
  • Д. Креншоу. Давайте создадим компилятор!.

Wikimedia Foundation. 2010.

Компиляция (программирование) — это… Что такое Компиляция (программирование)?

Компиля́тор —

  • Программа, предназначенная для трансляции высокоуровневого языка в абсолютный код или, иногда, в язык ассемблера. Входной информацией для компилятора (исходный код) является описание алгоритма или программа на проблемно-ориентированном языке, а на выходе компилятора — эквивалентное описание алгоритма на машинно-ориентированном языке (объектный код).[5]

Компиляция

  • Трансляция программы на язык, близкий к машинному.[3][2]
  • Трансляция программы, составленной на исходном языке, в объектный модуль. Осуществляется компилятором.[2]

Компилировать — проводить трансляцию машинной программы с проблемно-ориентированного языка на машинно-ориентированный язык.[3]

Виды компиляторов

[2]
  • Векторизующий. Транслирует исходный код в машинный код компьютеров, оснащённых векторным процессором.
  • Гибкий. Составлен по модульному принципу, управляется таблицами и запрограммирован на языке высокого уровня или реализован с помощью компилятора компиляторов.
  • Диалоговый. См.: диалоговый транслятор.
  • Инкрементальный. Повторно транслирует фрагменты программы и дополнения к ней без перекомпиляции всей программы.
  • Интерпретирующий (пошаговый). Последовательно выполняет независимую компиляцию каждого отдельного оператора (команды) исходной программы.
  • Компилятор компиляторов. Транслятор, воспринимающий формальное описание языка программирования и генерирующий компилятор для этого языка.
  • Отладочный. Устраняет отдельные виды синтаксических ошибок.
  • Резидентный. Постоянно находится в основной памяти и доступен для повторного использования многими задачами.
  • Самокомпилируемый. Написан на том же языке, с которого осуществляется трансляция.
  • Универсальный. Основан на формальном описании синтаксиса и семантики входного языка. Составными частями такого компилятора являются: ядро, синтаксический и семантический загрузчики.

Виды компиляции

[2]
  • Пакетная. Компиляция нескольких исходных модулей в одном пункте задания.
  • Построчная. То же, что и интерпретация.
  • Условная. Компиляция, при которой транслируемый текст зависит от условий, заданных в исходной программе. Так, в зависимости от значения некоторой константы, можно включать или выключать трансляцию части текста программы.

Основы

Большинство компиляторов переводит программу с некоторого высокоуровневого языка программирования в машинный код, который может быть непосредственно выполнен центральным процессором. Как правило, этот код также ориентирован на исполнение в среде конкретной операционной системы, поскольку использует предоставляемые ею возможности (системные вызовы, библиотеки функций). Архитектура (набор программно-аппаратных средств), для которой производится компиляция, называется целевой машиной.

Некоторые компиляторы (например, низкоуровневом языке. Такой язык — байт-код — также можно считать языком машинных команд, поскольку он подлежит интерпретации виртуальной машиной. Например, для языка Java это JVM (язык виртуальной машины Java), или так называемый байт-код Java (вслед за ним все промежуточные низкоуровневые языки стали называть байт-кодами). Для языков программирования на платформе .NET Framework (C#, Managed C++, Visual Basic .NET и другие) — это MSIL (Microsoft Intermediate Language).

Программа на байт-коде подлежит интерпретации виртуальной машиной, либо ещё одной компиляции уже в машинный код непосредственно перед исполнением. Последнее называется «Just-In-Time компиляция» (MSIL-код компилируется в код целевой машины также JIT-компилятором, а библиотеки .NET Framework компилируются заранее).

Для каждой целевой машины (Apple и т. д.) и каждой операционной системы или семейства операционных систем, работающих на целевой машине, требуется написание своего компилятора. Существуют также так называемые кросс-компиляторы, позволяющие на одной машине и в среде одной ОС получать код, предназначенный для выполнения на другой целевой машине и/или в среде другой ОС. Кроме того, компиляторы могут быть оптимизированы под разные типы процессоров из одного семейства (путём использования специфичных для этих процессоров инструкций). Например, код, скомпилированный под процессоры семейства MMX, SSE2.

Также существуют компиляторы, переводящие программу с языка высокого уровня на язык ассемблера.

Существуют программы, которые решают обратную задачу — перевод программы с низкоуровневого языка на высокоуровневый. Этот процесс называют декомпиляцией, а программы — декомпиляторами. Но поскольку компиляция — это процесс с потерями, точно восстановить исходный код, скажем, на C++, в общем случае невозможно. Более эффективно декомпилируются программы в байт-кодах — например, существует довольно надёжный декомпилятор для Flash. Сходным процессом является дизассемблирование машинного кода в код на языке ассемблера, который всегда выполняется успешно. Связано это с тем, что между кодами машинных команд и командами ассемблера имеется практически однозначное соответствие.

Структура компилятора

Процесс компиляции состоит из следующих этапов:

  1. Лексический анализ. На этом этапе последовательность символов исходного файла преобразуется в последовательность лексем.
  2. Синтаксический (грамматический) анализ. Последовательность лексем преобразуется в дерево разбора.
  3. Семантический анализ. Дерево разбора обрабатывается с целью установления его семантики (смысла) — например, привязка идентификаторов к их декларациям, типам, проверка совместимости, определение типов выражений и т. д. Результат обычно называется «промежуточным представлением/кодом», и может быть дополненным деревом разбора, новым деревом, абстрактным набором команд или чем-то ещё, удобным для дальнейшей обработки.
  4. Оптимизация. Выполняется удаление излишних конструкций и упрощение кода с сохранением его смысла. Оптимизация может быть на разных уровнях и этапах — например, над промежуточным кодом или над конечным машинным кодом.
  5. Генерация кода. Из промежуточного представления порождается код на целевом языке.

В конкретных реализациях компиляторов эти этапы могут быть раздельны или совмещены в том или ином виде.

Трансляция и компоновка

Важной исторической особенностью компилятора, отражённой в его названии (англ. compile — собирать вместе, составлять), являлось то, что он мог производить и компоновку (то есть содержал две части — транслятор и компоновщик). Это связано с тем, что раздельная компиляция и компоновка как отдельная стадия сборки выделились значительно позже появления компиляторов, и многие популярные компиляторы (например, GCC) до сих пор физически объединены со своими компоновщиками. В связи с этим, вместо термина «компилятор» иногда используют термин «транслятор» как его синоним: либо в старой литературе, либо когда хотят подчеркнуть его способность переводить программу в машинный код (и наоборот, используют термин «компилятор» для подчёркивания способности собирать из многих файлов один).

Интересные факты

  • На заре развития компьютеров первые компиляторы (трансляторы) называли «программирующими программами»[6] (так как в тот момент программой считался только машинный код, а «программирующая программа» была способна из человеческого текста сделать машинный код, то есть запрограммировать ЭВМ).

Примечания

  1. ГОСТ 19781-83 // Вычислительная техника. Терминология: Справочное пособие. Выпуск 1 / Рецензент канд. техн. наук Ю. П. Селиванов. — М.: Издательство стандартов, 1989. — 168 с. — 55 000 экз. — ISBN 5-7050-0155-X
  2. 1 2 3 4 5 6 7 Першиков В. И., Савинков В. М. Толковый словарь по информатике / Рецензенты: канд. физ.-мат. наук А. С. Марков и д-р физ.-мат. наук И. В. Поттосин. — М.: Финансы и статистика, 1991. — 543 с. — 50 000 экз. — ISBN 5-279-00367-0
  3. 1 2 3 СТ ИСО 2382/7-77 // Вычислительная техника. Терминология. Указ. соч.
  4. Борковский А. Б. Англо-русский словарь по программированию и информатике (с толкованиями). — М.: Русский язык, 1990. — 335 с. — 50 050 (доп.) экз. — ISBN 5-200-01169-3
  5. Толковый словарь по вычислительным системам = Dictionary of Computing / Под ред. В. Иллингуорта и др.: Пер. с англ. А. К. Белоцкого и др.; Под ред. Е. К. Масловского. — М.: Машиностроение, 1990. — 560 с. — 70 000 (доп.) экз. — ISBN 5-217-00617-X (СССР), ISBN 0-19-853913-4 (Великобритания)
  6. Н. А. Криницкий, Г. А. Миронов, Г. Д. Фролов. Программирование / Под ред. М. Р. Шура-Бура. — М.: Государственное издательство физико-математической литературы, 1963.

См. также

Реализации компиляторов

Литература

  • Альфред В. Ахо, Моника С. Лам, Рави Сети, Джеффри Д. Ульман. Компиляторы: принципы, технологии и инструментарий = Compilers: Principles, Techniques, and Tools. — 2-е изд. — М.: Вильямс, 2008. — ISBN 978-5-8459-1349-4
  • Робин Хантер. Основные концепции компиляторов = The Essence of Compilers. — М.: Вильямс, 2002. — С. 256. — ISBN 0-13-727835-7
  • Хантер Р. Проектирование и конструирование компиляторов / Пер. с англ. С. М. Круговой. — М.: Финансы и статистика, 1984. — 232 с.
  • Д. Креншоу. Давайте создадим компилятор!.

Wikimedia Foundation. 2010.

Интерпретация и компиляция в программировании

Одной из ключевых характеристик PHP является то, что это интерпретируемый язык программирования. С другой стороны, языки программирования наподобие C, изначально разрабатывались для компиляции. Что это значит?

Компилируется ли язык программирования или интерпретируется, на самом деле это не зависит от природы языка программирования. Любой язык программирования может интерпретироваться так называемым интерпретатором или компилироваться с помощью так называемого компилятора.

При использовании любого языка программирования существует определенный рабочий цикл создания кода. Вы пишете его, запускаете, находите ошибки и отлаживаете. Таким образом, вы переписываете и дописываете программу, проверяете ее. То, о чем пойдет речь в этой статье, это «запускаемая» часть программы.

Когда пишете программу, вы хотите, чтобы ее инструкции работали на компьютере. Компьютер обрабатывает информацию с помощью процессора, который поэтапно выполняет инструкции, закодированные в двоичном формате. Как из выражения «a = 3;» получить закодированные инструкции, которые процессор может понять?

Мы делаем это с помощью компиляции. Существует специальные приложения, известные как компиляторы. Они принимают программу, которую вы написали. Затем анализируют и разбирают каждую часть программы и строят машинный код для процессора. Часто его также называют объектным кодом.

На одном из этапов процесса обработки задействуется компоновщик, принимающий части программы, которые отдельно были преобразованы в объектный код, и связывает их в один исполняемый файл. Вот схема, описывающая данный процесс:

Конечным элементом этого процесса является исполняемый файл. Когда вы запускаете или сообщаете компьютеру, что это исполняемый файл, он берет первую же инструкцию из него, не фильтрует, не преобразует, а сразу запускает программу и выполняет ее без какого-либо дополнительного преобразования. Это ключевая характеристика процесса компиляции — его результат должен быть исполняемым файлом, не требующим дополнительного перевода, чтобы процессор мог начать выполнять первую инструкцию и все следующие за ней.

Первые компиляторы были написаны непосредственно через машинный код или с использованием ассемблеров. Но цель компилятора очевидна: перевести программу в исполняемый машинный код для конкретного процессора.

Некоторые языки программирования разрабатывались с учетом компиляции. C, например, предназначался для того, чтобы дать возможность программистам с легкостью реализовать разные вещи. Но в итоге он разрабатывался таким образом, чтобы его можно было легко перевести на машинный код. Компиляция в программировании это серьезно!

Не все языки программирования учитывают это в своей концепции. Например, Java предназначался для запуска в «интерпретирующей» среде, а Python всегда должен интерпретироваться.

Альтернативой компиляции является интерпретация. Чем отличаются компиляторы и интерпретаторы? Основная разница между компилятором и интерпретатором заключается в том, как они работают. Компилятор берет всю программу и преобразует ее в машинный код, который понимает процессор.

Интерпретатор — это исполняемый файл, который поэтапно читает программу, а затем обрабатывает, сразу выполняя ее инструкции.

Другими словами, программа-интерпретатор выполняет программу поэтапно как часть собственного исполняемого файла. Объектный код не передается процессору, интерпретатор сам является объектным кодом, построенным таким образом, чтобы его можно было вызвать в определенное время.

Это ломает рабочий цикл, который был приведен на диаграмме выше. Теперь у нас есть новая диаграмма:

На ней мы видим, что в отличии от компилятора, интерпретатор всегда должен быть под рукой, чтобы мы могли вызвать его и запустить нашу программу. В некотором смысле интерпретатор становится процессором. Программы, написанные для интерпретации, называются «скриптами», потому что они являются сценариями действий для другой программы, а не прямым машинным кодом.

Например, так работают такие языки программирования, как Python. Вы пишете программу. Затем вводите код в интерпретатор Python, и он выполняет все описанные вами шаги. В командной строке вы можете ввести примерно следующее:

В этой команде Python — это исполняемый файл. Вы вводите в него все, что находится в файле myprogram.py, и он выполняет эти инструкции. Компьютер не запустит myprogram.py без Python. Это не машинный код, который понимает процессор. Можно скомпилировать программы Python в объектный или машинный код и запустить его непосредственно в процессоре. Но эта процедура включает в себя компиляцию кода и добавление в качестве ее части всего интерпретатора Python.

Интерпретаторы могут создаваться по-разному. Существуют интерпретаторы, которые читают исходную программу и не выполняют дополнительной обработки. Они просто берут определенное количество строк кода за раз и выполняют его.

Некоторые интерпретаторы выполняют собственную компиляцию, но обычно преобразуют программу байтовый код, который имеет смысл только для интерпретатора. Это своего рода псевдо машинный язык, который понимает только интерпретатор.

Такой код быстрее обрабатывается, и его проще написать для исполнителя (части интерпретатора, которая исполняет), который считывает байтовый код, а не код источника.

Есть интерпретаторы, для которых этот вид байтового кода имеет более важное значение. Например, язык программирования Java «запускается» на так называемой виртуальной машине. Она является исполняемым кодом или частью программы, которая считывает конкретный байтовый код и эмулирует работу процессора. Обрабатывая байтовый код так, как если бы процессор компьютера был виртуальным процессором.

У меня есть эмулятор для игровой приставки NIntendo. Когда я загружаю ROM-файл Dragon Warrior, он форматируется в машинный код, который понимает только процессор NES. Но если я создаю виртуальный процессор, который интерпретирует байтовый код во время работы на другом процессоре, я могу запустить Dragon Warrior на любой машине с эмулятором.

Это использует концепция компиляции Java, а также все интерпретаторы. На любом процессоре, для которого я могу создать интерпретатор / эмулятор, можно запускать мои интерпретируемые программы / байтовый код. В этом заключается основное преимущество интерпретатора над компилятором.

Основным аргументом за использование процесса компиляции является скорость. Возможность компилировать любой программный код в машинный, который может понять процессор ПК, исключает использование промежуточного кода. Можно запускать программы без дополнительных шагов, тем самым увеличивая скорость обработки кода.

Но наибольшим недостатком компиляции является специфичность. Когда компилируете программу для работы на конкретном процессоре, вы создаете объектный код, который будет работать только на этом процессоре. Если хотите, чтобы программа запускалась на другой машине, вам придется перекомпилировать программу под этот процессор. А перекомпиляция может быть довольно сложной, если процессор имеет ограничения или особенности, не присущие первому. А также может вызывать ошибки компиляции.

Основное преимущество интерпретации — гибкость. Можно не только запускать интерпретируемую программу на любом процессоре или платформе, для которых интерпретатор был скомпилирован. Написанный интерпретатор может предложить дополнительную гибкость. В определенном смысле интерпретаторы проще понять и написать, чем компиляторы.

С помощью интерпретатора проще добавить дополнительные функции, реализовать такие элементы, как сборщики мусора, а не расширять язык.

Другим преимуществом интерпретаторов является то, что их проще переписать или перекомпилировать для новых платформ.

Написание компилятора для процессора требует добавления множества функций, или полной переработки. Но как только компилятор написан, можно скомпилировать кучу интерпретаторов и на выходе мы имеем перспективный язык. Не нужно повторно внедрять интерпретатор на базовом уровне для другого процессора.

Самым большим недостатком интерпретаторов является скорость. Для каждой программы выполняется так много переводов, фильтраций, что это приводит к замедлению работы и мешает выполнению программного кода.

Это проблема для конкретных real-time приложений, таких как игры с высоким разрешением и симуляцией. Некоторые интерпретаторы содержат компоненты, которые называются just-in-time компиляторами (JIT). Они компилируют программу непосредственно перед ее исполнением. Это специальные программы, вынесенные за рамки интерпретатора. Но поскольку процессоры становятся все более мощными, данная проблема становится менее актуальной.

Всегда июмейте всегда в виду, что некоторые языки программирования специально предназначены для компиляции кода, например, C. В то время как другие языки всегда должны интерпретироваться, например Java.

Для меня не имеет значения, скомпилировано что-то или интерпретировано, если оно может выполнить задачу эффективно.

Некоторые системы не предлагают технические условия для эффективного использования интерпретаторов. Поэтому вы должны запрограммировать их с помощью чего-то, что может быть непосредственно скомпилировано, например C. Иногда нужно выполнить вычисления настолько интенсивно, насколько это возможно. Например, при точном распознавании голоса роботом. В других случаях скорость или вычислительная мощность могут быть не столь критичными, и написать эмулятор на оригинальном языке может быть проще.

Сообщите мне, что бы вы предпочли: интерпретацию или компиляцию? Спасибо за уделенное время!

Пожалуйста, оставьте ваши комментарии по текущей теме статьи. Мы крайне благодарны вам за ваши комментарии, дизлайки, подписки, отклики, лайки!

Данная публикация является переводом статьи «Interpretation Versus Compilation» , подготовленная редакцией проекта.

Интерпретация и компиляция в программировании

Одной из ключевых характеристик PHP является то, что это интерпретируемый язык программирования. С другой стороны, языки программирования наподобие C, изначально разрабатывались для компиляции. Что это значит?

Компилируется ли язык программирования или интерпретируется, на самом деле это не зависит от природы языка программирования. Любой язык программирования может интерпретироваться так называемым интерпретатором или компилироваться с помощью так называемого компилятора.

При использовании любого языка программирования существует определенный рабочий цикл создания кода. Вы пишете его, запускаете, находите ошибки и отлаживаете. Таким образом, вы переписываете и дописываете программу, проверяете ее. То, о чем пойдет речь в этой статье, это «запускаемая» часть программы.

Когда пишете программу, вы хотите, чтобы ее инструкции работали на компьютере. Компьютер обрабатывает информацию с помощью процессора, который поэтапно выполняет инструкции, закодированные в двоичном формате. Как из выражения «a = 3;» получить закодированные инструкции, которые процессор может понять?

Мы делаем это с помощью компиляции. Существует специальные приложения, известные как компиляторы. Они принимают программу, которую вы написали. Затем анализируют и разбирают каждую часть программы и строят машинный код для процессора. Часто его также называют объектным кодом.

На одном из этапов процесса обработки задействуется компоновщик, принимающий части программы, которые отдельно были преобразованы в объектный код, и связывает их в один исполняемый файл. Вот схема, описывающая данный процесс:

Конечным элементом этого процесса является исполняемый файл. Когда вы запускаете или сообщаете компьютеру, что это исполняемый файл, он берет первую же инструкцию из него, не фильтрует, не преобразует, а сразу запускает программу и выполняет ее без какого-либо дополнительного преобразования. Это ключевая характеристика процесса компиляции — его результат должен быть исполняемым файлом, не требующим дополнительного перевода, чтобы процессор мог начать выполнять первую инструкцию и все следующие за ней.

Первые компиляторы были написаны непосредственно через машинный код или с использованием ассемблеров. Но цель компилятора очевидна: перевести программу в исполняемый машинный код для конкретного процессора.

Некоторые языки программирования разрабатывались с учетом компиляции. C, например, предназначался для того, чтобы дать возможность программистам с легкостью реализовать разные вещи. Но в итоге он разрабатывался таким образом, чтобы его можно было легко перевести на машинный код. Компиляция в программировании это серьезно!

Не все языки программирования учитывают это в своей концепции. Например, Java предназначался для запуска в «интерпретирующей» среде, а Python всегда должен интерпретироваться.

Альтернативой компиляции является интерпретация. Чем отличаются компиляторы и интерпретаторы? Основная разница между компилятором и интерпретатором заключается в том, как они работают. Компилятор берет всю программу и преобразует ее в машинный код, который понимает процессор.

Интерпретатор — это исполняемый файл, который поэтапно читает программу, а затем обрабатывает, сразу выполняя ее инструкции.

Другими словами, программа-интерпретатор выполняет программу поэтапно как часть собственного исполняемого файла. Объектный код не передается процессору, интерпретатор сам является объектным кодом, построенным таким образом, чтобы его можно было вызвать в определенное время.

Это ломает рабочий цикл, который был приведен на диаграмме выше. Теперь у нас есть новая диаграмма:

На ней мы видим, что в отличии от компилятора, интерпретатор всегда должен быть под рукой, чтобы мы могли вызвать его и запустить нашу программу. В некотором смысле интерпретатор становится процессором. Программы, написанные для интерпретации, называются «скриптами», потому что они являются сценариями действий для другой программы, а не прямым машинным кодом.

Например, так работают такие языки программирования, как Python. Вы пишете программу. Затем вводите код в интерпретатор Python, и он выполняет все описанные вами шаги. В командной строке вы можете ввести примерно следующее:

В этой команде Python — это исполняемый файл. Вы вводите в него все, что находится в файле myprogram.py, и он выполняет эти инструкции. Компьютер не запустит myprogram.py без Python. Это не машинный код, который понимает процессор. Можно скомпилировать программы Python в объектный или машинный код и запустить его непосредственно в процессоре. Но эта процедура включает в себя компиляцию кода и добавление в качестве ее части всего интерпретатора Python.

Интерпретаторы могут создаваться по-разному. Существуют интерпретаторы, которые читают исходную программу и не выполняют дополнительной обработки. Они просто берут определенное количество строк кода за раз и выполняют его.

Некоторые интерпретаторы выполняют собственную компиляцию, но обычно преобразуют программу байтовый код, который имеет смысл только для интерпретатора. Это своего рода псевдо машинный язык, который понимает только интерпретатор.

Такой код быстрее обрабатывается, и его проще написать для исполнителя (части интерпретатора, которая исполняет), который считывает байтовый код, а не код источника.

Есть интерпретаторы, для которых этот вид байтового кода имеет более важное значение. Например, язык программирования Java «запускается» на так называемой виртуальной машине. Она является исполняемым кодом или частью программы, которая считывает конкретный байтовый код и эмулирует работу процессора. Обрабатывая байтовый код так, как если бы процессор компьютера был виртуальным процессором.

У меня есть эмулятор для игровой приставки NIntendo. Когда я загружаю ROM-файл Dragon Warrior, он форматируется в машинный код, который понимает только процессор NES. Но если я создаю виртуальный процессор, который интерпретирует байтовый код во время работы на другом процессоре, я могу запустить Dragon Warrior на любой машине с эмулятором.

Это использует концепция компиляции Java, а также все интерпретаторы. На любом процессоре, для которого я могу создать интерпретатор / эмулятор, можно запускать мои интерпретируемые программы / байтовый код. В этом заключается основное преимущество интерпретатора над компилятором.

Основным аргументом за использование процесса компиляции является скорость. Возможность компилировать любой программный код в машинный, который может понять процессор ПК, исключает использование промежуточного кода. Можно запускать программы без дополнительных шагов, тем самым увеличивая скорость обработки кода.

Но наибольшим недостатком компиляции является специфичность. Когда компилируете программу для работы на конкретном процессоре, вы создаете объектный код, который будет работать только на этом процессоре. Если хотите, чтобы программа запускалась на другой машине, вам придется перекомпилировать программу под этот процессор. А перекомпиляция может быть довольно сложной, если процессор имеет ограничения или особенности, не присущие первому. А также может вызывать ошибки компиляции.

Основное преимущество интерпретации — гибкость. Можно не только запускать интерпретируемую программу на любом процессоре или платформе, для которых интерпретатор был скомпилирован. Написанный интерпретатор может предложить дополнительную гибкость. В определенном смысле интерпретаторы проще понять и написать, чем компиляторы.

С помощью интерпретатора проще добавить дополнительные функции, реализовать такие элементы, как сборщики мусора, а не расширять язык.

Другим преимуществом интерпретаторов является то, что их проще переписать или перекомпилировать для новых платформ.

Написание компилятора для процессора требует добавления множества функций, или полной переработки. Но как только компилятор написан, можно скомпилировать кучу интерпретаторов и на выходе мы имеем перспективный язык. Не нужно повторно внедрять интерпретатор на базовом уровне для другого процессора.

Самым большим недостатком интерпретаторов является скорость. Для каждой программы выполняется так много переводов, фильтраций, что это приводит к замедлению работы и мешает выполнению программного кода.

Это проблема для конкретных real-time приложений, таких как игры с высоким разрешением и симуляцией. Некоторые интерпретаторы содержат компоненты, которые называются just-in-time компиляторами (JIT). Они компилируют программу непосредственно перед ее исполнением. Это специальные программы, вынесенные за рамки интерпретатора. Но поскольку процессоры становятся все более мощными, данная проблема становится менее актуальной.

Всегда июмейте всегда в виду, что некоторые языки программирования специально предназначены для компиляции кода, например, C. В то время как другие языки всегда должны интерпретироваться, например Java.

Для меня не имеет значения, скомпилировано что-то или интерпретировано, если оно может выполнить задачу эффективно.

Некоторые системы не предлагают технические условия для эффективного использования интерпретаторов. Поэтому вы должны запрограммировать их с помощью чего-то, что может быть непосредственно скомпилировано, например C. Иногда нужно выполнить вычисления настолько интенсивно, насколько это возможно. Например, при точном распознавании голоса роботом. В других случаях скорость или вычислительная мощность могут быть не столь критичными, и написать эмулятор на оригинальном языке может быть проще.

Сообщите мне, что бы вы предпочли: интерпретацию или компиляцию? Спасибо за уделенное время!

Пожалуйста, оставьте ваши комментарии по текущей теме статьи. Мы крайне благодарны вам за ваши комментарии, дизлайки, подписки, отклики, лайки!

Данная публикация является переводом статьи «Interpretation Versus Compilation» , подготовленная редакцией проекта.

Интерпретация и компиляция в программировании

Одной из ключевых характеристик PHP является то, что это интерпретируемый язык программирования. С другой стороны, языки программирования наподобие C, изначально разрабатывались для компиляции. Что это значит?

Компилируется ли язык программирования или интерпретируется, на самом деле это не зависит от природы языка программирования. Любой язык программирования может интерпретироваться так называемым интерпретатором или компилироваться с помощью так называемого компилятора.

При использовании любого языка программирования существует определенный рабочий цикл создания кода. Вы пишете его, запускаете, находите ошибки и отлаживаете. Таким образом, вы переписываете и дописываете программу, проверяете ее. То, о чем пойдет речь в этой статье, это «запускаемая» часть программы.

Когда пишете программу, вы хотите, чтобы ее инструкции работали на компьютере. Компьютер обрабатывает информацию с помощью процессора, который поэтапно выполняет инструкции, закодированные в двоичном формате. Как из выражения «a = 3;» получить закодированные инструкции, которые процессор может понять?

Мы делаем это с помощью компиляции. Существует специальные приложения, известные как компиляторы. Они принимают программу, которую вы написали. Затем анализируют и разбирают каждую часть программы и строят машинный код для процессора. Часто его также называют объектным кодом.

На одном из этапов процесса обработки задействуется компоновщик, принимающий части программы, которые отдельно были преобразованы в объектный код, и связывает их в один исполняемый файл. Вот схема, описывающая данный процесс:

Конечным элементом этого процесса является исполняемый файл. Когда вы запускаете или сообщаете компьютеру, что это исполняемый файл, он берет первую же инструкцию из него, не фильтрует, не преобразует, а сразу запускает программу и выполняет ее без какого-либо дополнительного преобразования. Это ключевая характеристика процесса компиляции — его результат должен быть исполняемым файлом, не требующим дополнительного перевода, чтобы процессор мог начать выполнять первую инструкцию и все следующие за ней.

Первые компиляторы были написаны непосредственно через машинный код или с использованием ассемблеров. Но цель компилятора очевидна: перевести программу в исполняемый машинный код для конкретного процессора.

Некоторые языки программирования разрабатывались с учетом компиляции. C, например, предназначался для того, чтобы дать возможность программистам с легкостью реализовать разные вещи. Но в итоге он разрабатывался таким образом, чтобы его можно было легко перевести на машинный код. Компиляция в программировании это серьезно!

Не все языки программирования учитывают это в своей концепции. Например, Java предназначался для запуска в «интерпретирующей» среде, а Python всегда должен интерпретироваться.

Альтернативой компиляции является интерпретация. Чем отличаются компиляторы и интерпретаторы? Основная разница между компилятором и интерпретатором заключается в том, как они работают. Компилятор берет всю программу и преобразует ее в машинный код, который понимает процессор.

Интерпретатор — это исполняемый файл, который поэтапно читает программу, а затем обрабатывает, сразу выполняя ее инструкции.

Другими словами, программа-интерпретатор выполняет программу поэтапно как часть собственного исполняемого файла. Объектный код не передается процессору, интерпретатор сам является объектным кодом, построенным таким образом, чтобы его можно было вызвать в определенное время.

Это ломает рабочий цикл, который был приведен на диаграмме выше. Теперь у нас есть новая диаграмма:

На ней мы видим, что в отличии от компилятора, интерпретатор всегда должен быть под рукой, чтобы мы могли вызвать его и запустить нашу программу. В некотором смысле интерпретатор становится процессором. Программы, написанные для интерпретации, называются «скриптами», потому что они являются сценариями действий для другой программы, а не прямым машинным кодом.

Например, так работают такие языки программирования, как Python. Вы пишете программу. Затем вводите код в интерпретатор Python, и он выполняет все описанные вами шаги. В командной строке вы можете ввести примерно следующее:

В этой команде Python — это исполняемый файл. Вы вводите в него все, что находится в файле myprogram.py, и он выполняет эти инструкции. Компьютер не запустит myprogram.py без Python. Это не машинный код, который понимает процессор. Можно скомпилировать программы Python в объектный или машинный код и запустить его непосредственно в процессоре. Но эта процедура включает в себя компиляцию кода и добавление в качестве ее части всего интерпретатора Python.

Интерпретаторы могут создаваться по-разному. Существуют интерпретаторы, которые читают исходную программу и не выполняют дополнительной обработки. Они просто берут определенное количество строк кода за раз и выполняют его.

Некоторые интерпретаторы выполняют собственную компиляцию, но обычно преобразуют программу байтовый код, который имеет смысл только для интерпретатора. Это своего рода псевдо машинный язык, который понимает только интерпретатор.

Такой код быстрее обрабатывается, и его проще написать для исполнителя (части интерпретатора, которая исполняет), который считывает байтовый код, а не код источника.

Есть интерпретаторы, для которых этот вид байтового кода имеет более важное значение. Например, язык программирования Java «запускается» на так называемой виртуальной машине. Она является исполняемым кодом или частью программы, которая считывает конкретный байтовый код и эмулирует работу процессора. Обрабатывая байтовый код так, как если бы процессор компьютера был виртуальным процессором.

У меня есть эмулятор для игровой приставки NIntendo. Когда я загружаю ROM-файл Dragon Warrior, он форматируется в машинный код, который понимает только процессор NES. Но если я создаю виртуальный процессор, который интерпретирует байтовый код во время работы на другом процессоре, я могу запустить Dragon Warrior на любой машине с эмулятором.

Это использует концепция компиляции Java, а также все интерпретаторы. На любом процессоре, для которого я могу создать интерпретатор / эмулятор, можно запускать мои интерпретируемые программы / байтовый код. В этом заключается основное преимущество интерпретатора над компилятором.

Основным аргументом за использование процесса компиляции является скорость. Возможность компилировать любой программный код в машинный, который может понять процессор ПК, исключает использование промежуточного кода. Можно запускать программы без дополнительных шагов, тем самым увеличивая скорость обработки кода.

Но наибольшим недостатком компиляции является специфичность. Когда компилируете программу для работы на конкретном процессоре, вы создаете объектный код, который будет работать только на этом процессоре. Если хотите, чтобы программа запускалась на другой машине, вам придется перекомпилировать программу под этот процессор. А перекомпиляция может быть довольно сложной, если процессор имеет ограничения или особенности, не присущие первому. А также может вызывать ошибки компиляции.

Основное преимущество интерпретации — гибкость. Можно не только запускать интерпретируемую программу на любом процессоре или платформе, для которых интерпретатор был скомпилирован. Написанный интерпретатор может предложить дополнительную гибкость. В определенном смысле интерпретаторы проще понять и написать, чем компиляторы.

С помощью интерпретатора проще добавить дополнительные функции, реализовать такие элементы, как сборщики мусора, а не расширять язык.

Другим преимуществом интерпретаторов является то, что их проще переписать или перекомпилировать для новых платформ.

Написание компилятора для процессора требует добавления множества функций, или полной переработки. Но как только компилятор написан, можно скомпилировать кучу интерпретаторов и на выходе мы имеем перспективный язык. Не нужно повторно внедрять интерпретатор на базовом уровне для другого процессора.

Самым большим недостатком интерпретаторов является скорость. Для каждой программы выполняется так много переводов, фильтраций, что это приводит к замедлению работы и мешает выполнению программного кода.

Это проблема для конкретных real-time приложений, таких как игры с высоким разрешением и симуляцией. Некоторые интерпретаторы содержат компоненты, которые называются just-in-time компиляторами (JIT). Они компилируют программу непосредственно перед ее исполнением. Это специальные программы, вынесенные за рамки интерпретатора. Но поскольку процессоры становятся все более мощными, данная проблема становится менее актуальной.

Всегда июмейте всегда в виду, что некоторые языки программирования специально предназначены для компиляции кода, например, C. В то время как другие языки всегда должны интерпретироваться, например Java.

Для меня не имеет значения, скомпилировано что-то или интерпретировано, если оно может выполнить задачу эффективно.

Некоторые системы не предлагают технические условия для эффективного использования интерпретаторов. Поэтому вы должны запрограммировать их с помощью чего-то, что может быть непосредственно скомпилировано, например C. Иногда нужно выполнить вычисления настолько интенсивно, насколько это возможно. Например, при точном распознавании голоса роботом. В других случаях скорость или вычислительная мощность могут быть не столь критичными, и написать эмулятор на оригинальном языке может быть проще.

Сообщите мне, что бы вы предпочли: интерпретацию или компиляцию? Спасибо за уделенное время!

Пожалуйста, оставьте ваши комментарии по текущей теме статьи. Мы крайне благодарны вам за ваши комментарии, дизлайки, подписки, отклики, лайки!

Данная публикация является переводом статьи «Interpretation Versus Compilation» , подготовленная редакцией проекта.

Процесс компиляции. Многие из нас пишут коды и выполняют… | Сибасиш Гош | Coding Den

Многие из нас пишут коды и исполняют их. Но все ли мы (ну, в основном новичок, я думаю: P) знаем основной процесс, который преобразует исходный код в исполняемую программу? Думаю, не много. Что ж, эта статья для всех тех Not-Many , которые ищут секрет;)

Image Source — worldcomputerar article

«Программисты пишут программы в форме, называемой исходным кодом.Исходный код должен пройти несколько этапов, прежде чем он станет исполняемой программой. Первым шагом является передача исходного кода через компилятор , который переводит инструкции языка высокого уровня в объектный код. Компоновщик объединяет модули и дает реальные значения всем символьным адресам, тем самым создавая машинный код ».

Вышеупомянутые строки объясняют весь процесс компиляции. Итак, в основном у вас есть программа, называемая исходным кодом , , которая должна пройти процесс компиляции для получения вывода с помощью исполняемой программы .

Итак, если есть процесс «компиляции», должен быть инструмент для выполнения этой работы. Да, есть одна такая вещь, известная под названием компилятор . Теперь давайте посмотрим, что такое компилятор.

Источник изображения — CraftingInterpreters

Компилятор — это специальная программа, которая обрабатывает операторы, написанные на определенном языке программирования, и превращает их в машинный язык или «код», который использует процессор компьютера. Обычно программист пишет операторы языка на языке, таком как Паскаль или Си, по одной строке за раз, используя редактор .Созданный файл содержит так называемые исходные операторы . Затем программист запускает компилятор соответствующего языка, указывая имя файла, содержащего исходные операторы.

При выполнении (запуске) компилятор сначала анализирует (или анализирует) все операторы языка синтаксически один за другим, а затем, на одном или нескольких последовательных этапах или «проходах», строит выходной код, проверяя, что операторы, которые ссылаться на другие операторы правильно упоминаются в окончательном коде.Традиционно выходные данные компиляции назывались объектным кодом или иногда объектным модулем . Объектный код — это машинный код, который процессор может выполнять по одной инструкции за раз.

Традиционно в некоторых операционных системах после компиляции требовался дополнительный этап — определение относительного расположения инструкций и данных, когда одновременно должно было выполняться несколько объектных модулей, и они перекрестно ссылались на последовательности инструкций друг друга. или данные.Этот процесс иногда назывался редактированием связи , а результат — загрузочным модулем .

Компилятор работает с так называемыми 3GL и языками более высокого уровня. Ассемблер работает с программами, написанными на языке ассемблера процессора.

(Источник — WhatIs )

Существуют определенные языки программирования, которые не компилируют исходный код. Так можно ли их казнить? К счастью или к сожалению, это вполне возможно.Ответ — с помощью переводчиков.

В информатике интерпретатор — это компьютерная программа, которая непосредственно выполняет, т.е. выполняет инструкций, написанных на языке программирования или сценариях, не требуя их предварительной компиляции в программу на машинном языке. Интерпретатор обычно использует одну из следующих стратегий для выполнения программы:

1. Анализировать исходный код и напрямую выполнять его поведение;

2.Преобразуйте исходный код в какое-нибудь эффективное промежуточное представление и немедленно выполните его;

3. Явно выполнить сохраненный предварительно скомпилированный код, созданный компилятором, который является частью системы интерпретатора.

Ранние версии языка программирования Lisp и Dartmouth BASIC будут примерами первого типа. Perl, Python, MATLAB и Ruby являются примерами второго типа, а UCSD Pascal — примером третьего типа.

(Источник — Википедия )

Хорошо, я закончил большую часть теоретической части.Чтобы понять, как это работает на самом деле, давайте воспользуемся помощью известного языка программирования — C ++.

Компиляция программы на C ++ включает три этапа:

1. Предварительная обработка: препроцессор берет файл с исходным кодом C ++ и обрабатывает #include ’ s, #define’ s и другие директивы препроцессора. Результатом этого шага является «чистый» файл C ++ без директив препроцессора.

2. Компиляция: компилятор берет вывод препроцессора и создает из него объектный файл.

3. Связывание: компоновщик берет объектные файлы, созданные компилятором, и создает либо библиотеку, либо исполняемый файл.

1. Предварительная обработка

Препроцессор обрабатывает директивы препроцессора , такие как #include и #define . Он не зависит от синтаксиса C ++, поэтому его следует использовать с осторожностью.

Он работает с одним исходным файлом C ++ за раз, заменяя директивы #include содержимым соответствующих файлов (обычно это просто объявления), выполняя замену макросов ( #define ) и выбирая разные части текст в зависимости от директив #if , #ifdef и #ifndef .

Препроцессор работает с потоком токенов предварительной обработки. Макрозамена определяется как замена токенов другими токенами (оператор ## позволяет объединить два токена, когда это имеет смысл).

После всего этого препроцессор производит единственный вывод, который представляет собой поток токенов, полученных в результате преобразований, описанных выше. Он также добавляет некоторые специальные маркеры, которые сообщают компилятору, откуда взялась каждая строка, чтобы он мог использовать их для создания разумных сообщений об ошибках.

Некоторые ошибки могут возникнуть на этом этапе при грамотном использовании директив #if и #error .

2. Компиляция

Этап компиляции выполняется на каждом выходе препроцессора. Компилятор анализирует чистый исходный код C ++ (теперь без каких-либо директив препроцессора) и преобразует его в код сборки. Затем вызывает базовый сервер (ассемблер в инструментальной цепочке), который собирает этот код в машинный код, создавая фактический двоичный файл в некотором формате (ELF, COFF, a.из и т. д.). Этот объектный файл содержит скомпилированный код (в двоичной форме) символов, определенных во входных данных. Символы в объектных файлах называются по имени.

Объектные файлы могут ссылаться на символы, которые не определены. Это тот случай, когда вы используете декларацию и не даете ей определения. Компилятор не возражает против этого и с радостью создаст объектный файл, если исходный код правильно сформирован.

Обычно компиляторы позволяют остановить компиляцию на этом этапе. Это очень полезно, потому что с его помощью вы можете компилировать каждый файл исходного кода отдельно.Преимущество этого заключается в том, что вам не нужно перекомпилировать все , если вы изменяете только один файл.

Созданные объектные файлы могут быть помещены в специальные архивы, называемые статическими библиотеками, для облегчения повторного использования в дальнейшем.

Именно на этом этапе выявляются «обычные» ошибки компилятора, такие как синтаксические ошибки или ошибки с ошибками разрешения перегрузки.

3. Связывание

Компоновщик — это то, что производит окончательный вывод компиляции из объектных файлов, созданных компилятором.Этот вывод может быть либо разделяемой (или динамической) библиотекой (и, хотя название похоже, у них нет много общего со статическими библиотеками, упомянутыми ранее), либо исполняемым файлом.

Он связывает все объектные файлы, заменяя ссылки на неопределенные символы правильными адресами. Каждый из этих символов может быть определен в других объектных файлах или в библиотеках. Если они определены в библиотеках, отличных от стандартной, вам необходимо сообщить о них компоновщику.

На этом этапе наиболее распространенными ошибками являются отсутствие определений или дублирование определений.Первое означает, что либо определения не существуют (т.е. они не записаны), либо объектные файлы или библиотеки, в которых они находятся, не были переданы компоновщику. Последнее очевидно: один и тот же символ был определен в двух разных объектных файлах или библиотеках.

(Источник — stackoverflow )

Итак, в следующий раз, когда вы запустите код, помните, что это чертовски много основного процесса! Доброго времени суток, amigos 🙂

Что такое компилятор? — Определение от WhatIs.com

От

Компилятор — это специальная программа, которая обрабатывает операторы, написанные на определенном языке программирования, и превращает их в машинный язык или «код», который использует процессор компьютера. Обычно программист пишет операторы языка на таком языке, как Паскаль или Си, по одной строке за раз, используя редактор . Созданный файл содержит так называемые исходные операторы . Затем программист запускает компилятор соответствующего языка, указывая имя файла, содержащего исходные операторы.

При выполнении (запуске) компилятор сначала анализирует (или анализирует) все операторы языка синтаксически один за другим, а затем, на одном или нескольких последовательных этапах или «проходах», строит выходной код, следя за тем, чтобы операторы, которые ссылаются на к другим операторам в окончательном коде относятся правильно. Традиционно выходные данные компиляции называются объектным кодом или иногда объектным модулем . (Обратите внимание, что термин «объект» здесь не имеет отношения к объектно-ориентированному программированию.) Объектный код — это машинный код, который процессор может выполнять по одной инструкции за раз.

Язык программирования Java, язык, используемый в объектно-ориентированном программировании, представил возможность компиляции вывода (называемого байт-кодом), который может работать на любой платформе компьютерной системы, для которой предоставляется виртуальная машина Java или интерпретатор байт-кода для преобразования байт-кода в инструкции. который может выполняться фактическим аппаратным процессором. Используя эту виртуальную машину, байт-код может быть дополнительно перекомпилирован на платформе исполнения с помощью своевременного компилятора.(См. Также: компилятор Java)

Традиционно в некоторых операционных системах после компиляции требовался дополнительный этап — определение относительного расположения инструкций и данных, когда более одного объектного модуля должны были запускаться одновременно, и они перекрестно ссылались на последовательности инструкций друг друга или данные. Этот процесс иногда назывался редактированием связи , а результат — загрузочным модулем .

Компилятор работает с языками, которые иногда называют 3GL, и языками более высокого уровня.Ассемблер работает с программами, написанными на языке ассемблера процессора.

Последнее обновление: сентябрь 2016 г.

Продолжить чтение о компиляторе

Компиляция программы C: — За кулисами

C — это язык среднего уровня, и ему нужен компилятор для преобразования его в исполняемый код, чтобы программу можно было запускать на нашей машине.

Как скомпилировать и запустить программу на языке C?
Ниже приведены шаги, которые мы используем на машине Ubuntu с компилятором gcc.

  • Сначала мы создаем программу на языке C с помощью редактора и сохраняем файл как filename.c
  $ vi filename.c  
  • На схеме справа показана простая программа для сложения двух чисел.

  • Затем скомпилируйте его, используя команду ниже.
  $ gcc –Wall filename.c –o filename  
  • Параметр -Wall включает все предупреждающие сообщения компилятора. Этот вариант рекомендуется для создания лучшего кода.
    Параметр -o используется для указания имени выходного файла. Если мы не используем эту опцию, то создается выходной файл с именем a.out.



  • После создания исполняемого файла компиляции мы запускаем сгенерированный исполняемый файл, используя команду ниже.
  $ ./filename  

Что происходит внутри процесса компиляции?
Компилятор преобразует программу на языке C в исполняемый файл. Чтобы программа C стала исполняемым файлом, существует четыре этапа:

  1. Предварительная обработка
  2. Компиляция
  3. Сборка
  4. Связывание

Выполнив команду ниже, мы получаем все промежуточные файлы в текущем каталоге вместе с исполняемым файлом. .

  $ gcc –Wall –save-temps filename.c –o filename  

На следующем снимке экрана показаны все сгенерированные промежуточные файлы.

Давайте по очереди посмотрим, что содержат эти промежуточные файлы.

Предварительная обработка

Это первая фаза, через которую проходит исходный код. Этот этап включает:

  • Удаление комментариев
  • Расширение макросов
  • Расширение включенных файлов.
  • Условная компиляция

Предварительно обработанный вывод сохраняется в имени файла .i . Давайте посмотрим, что находится внутри filename.i: using $ vi filename.i
В приведенном выше выводе исходный файл заполнен большим количеством информации, но в конце концов наш код сохраняется.
Анализ:



  • printf теперь содержит a + b, а не добавляет (a, b), потому что макросы расширились.
  • Комментарии удалены.
  • #include отсутствует, вместо этого мы видим много кода. Таким образом, файлы заголовков были расширены и включены в наш исходный файл.

Компиляция

Следующим шагом является компиляция filename.i и создание файла; промежуточный скомпилированный выходной файл filename.s . Этот файл находится в инструкциях уровня сборки. Давайте посмотрим на этот файл, используя $ vi filename.s

Снимок показывает, что он написан на языке ассемблера, который ассемблер может понять.

Сборка
На этом этапе filename.s берется в качестве входных данных и преобразуется ассемблером в filename.o . Этот файл содержит инструкции машинного уровня. На этом этапе только существующий код преобразуется в машинный язык, вызовы функций, такие как printf (), не разрешаются. Давайте рассмотрим этот файл, используя $ vi filename.o

Связывание

Это заключительный этап, на котором выполняется связывание всех вызовов функций с их определениями.Компоновщик знает, где реализованы все эти функции. Компоновщик также выполняет некоторую дополнительную работу, он добавляет некоторый дополнительный код в нашу программу, который требуется при запуске и завершении программы. Например, есть код, который требуется для настройки среды, например, для передачи аргументов командной строки. Эту задачу можно легко проверить, используя $ size filename.o и $ size filename . С помощью этих команд мы знаем, как выходной файл увеличивается от объектного файла до исполняемого файла.Это связано с дополнительным кодом, который компоновщик добавляет в нашу программу.

Обратите внимание, что GCC по умолчанию выполняет динамическое связывание, поэтому printf () динамически связан в вышеуказанной программе. Обратитесь к this, this и this для получения более подробной информации о статических и динамических связях.
Автор статьи: Vikash Kumar . Пожалуйста, напишите комментарии, если вы обнаружите что-то неправильное, или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.

1.1 Что такое компилятор?

1.1 Что такое компилятор?
Далее: 1.2 Что такое Up: 1 Введение Пред .: 1 Введение Содержание

Компилятор — это программа, которая переводит исходную программу, написанную на каком-то языке программирования высокого уровня (например, Java) в машину код для некоторой компьютерной архитектуры (например, Intel Pentium архитектура). Сгенерированный машинный код может быть позже выполнен на многих раз против разных данных каждый раз.

Интерпретатор читает исполняемую исходную программу, написанную на язык программирования высокого уровня, а также данные для этой программы, и он запускает программу на основе данных для получения некоторых результатов. Один пример — интерпретатор оболочки Unix, который запускает операционную систему команды в интерактивном режиме.

Обратите внимание, что и интерпретаторы, и компиляторы (как и любая другая программа) написан на каком-то языке программирования высокого уровня (который может быть отличается от языка, который они принимают), и они переведены на Машинный код.Например, интерпретатор Java может быть полностью написано на C или даже на Java. Исходная программа интерпретатора машинно-независимый, поскольку он не генерирует машинный код. (Обратите внимание разница между сгенерирована и переведена в машину кода.) Интерпретатор обычно медленнее, чем компилятор, потому что он обрабатывает и интерпретирует каждый оператор в программе столько раз, сколько количество оценок этого утверждения. Например, когда for-loop интерпретируется, операторы внутри тела for-loop будут анализироваться и оцениваться на каждом этапе цикла.Некоторые языки, например Java и Lisp поставляются с интерпретатором и компилятором. Ява исходные программы (классы Java с расширением .java ) являются переведены компилятором javac в файлы с байтовым кодом (с .class расширение). Интерпретатор Java, называемый виртуальная машина Java (JVM) может фактически интерпретировать байтовые коды напрямую или может внутренне скомпилировать их в машинный код, а затем выполнить этот код (JIT: ​​своевременная компиляция).

Составители и интерпретаторы — не единственные примеры переводчиков.Вот еще несколько:

Исходный язык Переводчик Целевой язык
LaTeX Средство форматирования текста PostScript
SQL процессор запросов к базе данных План оценки запросов
Java компилятор javac Байт-код Java
Java кросс-компилятор Код C ++
Текст на английском языке Понимание естественного языка семантика (значение)
Регулярные выражения Сканер-генератор JLex сканер на Java
БНФ языка Генератор парсера CUP парсер на Java
Этот курс в основном посвящен компиляторам для высокоуровневого программирования. языков, но те же методы применимы к переводчикам или любым другим схема составления.

Далее: 1.2 Что такое Up: 1 Введение Пред .: 1 Введение Содержание
2015-01-20

В чем разница между скомпилированной и интерпретируемой программой?

Этот контент был заархивирован и больше не поддерживается Университетом Индианы. Информация здесь может быть неточной, а ссылки могут быть недоступны или надежны.

Большинство программ написано на языке высокого уровня, таком как C, Perl или Java.Как человек язык позволяет людям легко общаться друг с другом, поэтому компьютерные языки упрощают задание компьютеру, что ему делать. Однако, поскольку компьютер понимает только числа, разговаривая с одним это похоже на разговор с кем-то, с кем вы не говорите на одном языке. Ты нужен переводчик для правильного общения, и вот что интерпретаторы и компиляторы делают.

Разница между интерпретируемым и компилируемым языком заключается в результат процесса интерпретации или компиляции.Интерпретатор выдает результат из программы, а компилятор создает программу написано на ассемблере. Сборщик архитектуры затем превращает полученную программу в двоичный код. сборка язык варьируется для каждого отдельного компьютера, в зависимости от его архитектура. Следовательно, скомпилированные программы могут работать только на компьютеры с той же архитектурой, что и компьютер, на котором они были составлены.

Скомпилированная программа не читается человеком, но вместо этого находится в машинный язык, специфичный для архитектуры.Создание скомпилированной программы требуется несколько шагов. Во-первых, программист с помощью разработки инструмент или даже простой текстовый редактор, записывает исходный код в выбранном компьютерный язык. Если программа сложная, ее части могут быть разложить по нескольким файлам. Затем программист компилирует программа, сортируя и связывая модули и переводя все это в машинный код, который понимает компьютер.

Потому что разные типы компьютеров не говорят на машинах друг друга языков, скомпилированная программа будет работать только на той платформе, на которой она была предназначен для.Например, программа, написанная для HP-UX обычно не работает на компьютере Mac OS или компьютере под управлением Solaris. Несмотря на этот недостаток, скомпилированные программы быстрее, чем те, которые должны выполняться через интерпретатор. Также, часто можно перекомпилировать программу, чтобы она работала на разные платформы. Примеры языков, которые обычно используются для создавать скомпилированные программы, включая C, Fortran и КОБОЛ.

В интерпретируемой программе, с другой стороны, исходный код обычно это программа.Программы этого типа (часто известные как скрипты) требуют интерпретатора, который анализирует команды в программа, а затем выполняет их. Некоторые переводчики, такие как Оболочки Unix ( sh , csh , ksh и т. Д.), Прочтите, а затем немедленно выполните каждый команда, в то время как другие, такие как Perl, анализируют весь сценарий перед отправка соответствующих инструкций на машинном языке. Преимущество сценария в том, что он очень переносимый. Любой компьютер с установленный соответствующий интерпретатор может более или менее запускать программу без изменений.Это тоже недостаток, потому что программа не запускаться вообще, если интерпретатор недоступен. В общем, интерпретируемые программы медленнее, чем скомпилированные, но проще отлаживать и исправлять. Другие примеры интерпретируемых языков включают JavaScript и Python.

Относится к программам, скомпилированным и интерпретируемым для конкретных компьютеров сценарии — это программы, разработанные для сред выполнения. Java и Таким образом выполняются программы Smalltalk. Создание программ для сред выполнения аналогично написанию традиционные компилированные программы.Разница в том, что вместо компилируя исходный код на машинный язык, он выводится в байтовый код для «виртуальной машины» среды выполнения. Эта виртуальная машина перехватывает инструкции байтового кода и переводит их в компьютерные команды. Преимущество этого подход заключается в том, что среда выполнения быстро компилирует только необходимые фрагменты кода (некоторые части программы могут никогда не понадобиться быть казненным). Это называется своевременной компиляцией. Главным Недостатком среды выполнения является то, что программа, которая не хорошо спроектированный заставит среду выполнения скомпилировать почти все кода заранее, а затем выполните избыточные вызовы устный переводчик.Это замедляет загрузку и выполнение программы.

Как работают компиляторы | Баелдунг по информатике

Мы открываем новую область компьютерных наук. Если у вас есть несколько лет опыта в области компьютерных наук или исследований, и вы заинтересованы в том, чтобы поделиться этим опытом с сообществом (и, конечно же, получать деньги за свою работу), загляните на страницу «Напишите для нас». Ура, Евгений

1. Введение

языков программирования были созданы, чтобы позволить разработчикам писать понятный человеку исходный код.Однако компьютеры работают с машинным кодом, который люди с трудом могут писать или читать. Таким образом, компиляторы переводят исходный код языка программирования в машинный код, предназначенный для конкретной машины .

В этой статье мы разберем этапы процесса компиляции. Затем мы увидим различия между компиляторами и интерпретаторами. Наконец, мы познакомим вас с примерами нескольких компиляторов современных языков программирования.

2. Этапы компиляции

Как мы уже упоминали, процесс компиляции преобразует исходный код высокого уровня в машинный код низкого уровня, который может выполняться целевой машиной.Более того, важная роль компиляторов — информировать разработчика о допущенных ошибках, особенно связанных с синтаксисом.

Процесс компиляции состоит из нескольких этапов:

  1. Лексический анализ
  2. Синтаксический анализ
  3. Семантический анализ
  4. Генерация промежуточного кода
  5. Оптимизация
  6. Кодовое поколение

В этом разделе мы подробно обсудим каждый этап.

2.1. Лексический анализ

Первым этапом компиляции является лексический анализ.На этом этапе компилятор разбивает исходный код на фрагменты, называемые лексемами. Лексема — это абстрактная единица лексической системы определенного языка. Давайте проанализируем простой пример:

  Строковое приветствие = "привет";  

В приведенном выше утверждении у нас пять лексем:

  1. Строка
  2. приветствие
  3. =
  4. «привет»
  5. ;

После разделения кода на лексемы создается последовательность токенов.Последовательность токенов — это конечный продукт лексического анализа. Таким образом, лексический анализ также часто называют токенизацией. Токен — это объект, описывающий лексему. Он предоставляет информацию о назначении лексемы, например о том, является ли она ключевым словом, именем переменной или строковым литералом. Кроме того, в нем хранятся данные о местоположении исходного кода лексемы.

2.2. Синтаксический анализ

Во время синтаксического анализа компилятор использует последовательность токенов, сгенерированных на первом этапе. Токены используются для создания структуры, называемой абстрактным синтаксическим деревом (AST), которая представляет собой дерево, представляющее логическую структуру программы.

На этом этапе компилятор проверяет грамматическую структуру исходного кода и правильность его синтаксиса. Между тем, любые синтаксические ошибки приводят к ошибке компиляции, о которой компилятор сообщает разработчику.

Короче говоря, синтаксический анализ отвечает за две задачи:

  1. Проверяет исходный код на наличие синтаксических ошибок.
  2. Он генерирует абстрактное синтаксическое дерево, которое использует следующий этап.

2.3. Семантический анализ

На этом этапе компилятор использует абстрактное синтаксическое дерево для обнаружения любых семантических ошибок, например:

  • присвоение переменной неправильного типа
  • объявление переменных с одинаковыми именами в одной области действия
  • с использованием необъявленной переменной
  • с использованием ключевого слова языка в качестве имени переменной

Семантический анализ можно разделить на три этапа:

  1. Проверка типа — проверяет соответствие типа в операторах присваивания, арифметических операциях, функциях и вызовах методов.
  2. Проверка управления потоком — исследует, правильно ли используются структуры управления потоком и правильно ли осуществляется доступ к классам и объектам.
  3. Проверка метки — подтверждает использование меток и идентификаторов.

Для достижения всех вышеперечисленных целей во время семантического анализа компилятор выполняет полный обход абстрактного синтаксического дерева. Семантический анализ, наконец, создает аннотированный AST, который описывает значения его атрибутов.

2.4. Генерация промежуточного кода

В процессе компиляции компилятор может сгенерировать одну или несколько промежуточных форм кода.

«После синтаксического и семантического анализа исходной программы многие компиляторы генерируют явное низкоуровневое или машиноподобное промежуточное представление, которое мы можем рассматривать как программу для абстрактной машины. Это промежуточное представление должно обладать двумя важными свойствами: его легко создавать и легко переводить на целевую машину ». — Компиляторы. Принципы, методы и инструменты. Второе издание. Альфред В. Ахо. Колумбийский университет.Моника С. Лам. Стэндфордский Университет. Рави Сетхи. Avaya.

Промежуточный код не зависит от машины. Таким образом, нет необходимости в уникальных компиляторах для каждой отдельной машины . Кроме того, методы оптимизации легче применять к промежуточному коду, чем к машинному коду. Промежуточный код имеет две формы представления:

  1. High-Level — аналогично исходному языку. В этой форме мы можем легко повысить производительность исходного кода.Однако он менее предпочтителен для повышения производительности целевой машины.
  2. Низкий уровень — близко к машинному коду машины. Это предпочтительнее для оптимизации машин.

2,5. Оптимизация

На этапе оптимизации компилятор использует различные способы повышения эффективности кода . Безусловно, процесс оптимизации должен следовать трем важным правилам:

  1. Полученный код не может изменить исходное значение программы.
  2. Оптимизация должна быть направлена ​​на потребление меньшего количества ресурсов и ускорение работы программного обеспечения.
  3. Процесс оптимизации не должен существенно влиять на общее время компиляции.

Давайте посмотрим на несколько примеров методов оптимизации:

  1. Встраивание функции — замена вызова функции ее телом.
  2. Устранение мертвого кода — компилятор избавляется от кода, который никогда не выполняется, или, если он выполняется, возвращенный результат не используется.
  3. Слияние циклов — выполнение в одном цикле операций из соседних циклов, которые имеют одинаковые условия итерации.
  4. Комбинирование инструкций — инструкции, реализующие аналогичные операции, объединяются в одну; например, x = x + 10; х = х — 7; можно заменить на x = x + 3;

2,6. Генерация кода

Наконец, компилятор преобразует оптимизированный промежуточный код в машинный код, выделенный для целевой машины.Окончательный код должен иметь то же значение, что и исходный код, и быть эффективным с точки зрения использования памяти и ресурсов ЦП. Кроме того, процесс генерации кода также должен быть эффективным.

2,7. Практический пример

На приведенной ниже блок-схеме мы видим пример процесса компиляции простого оператора.

3. Компилятор против интерпретатора

Как мы уже знаем, компилятор преобразует исходный код высокого уровня в код низкого уровня. Затем целевая машина выполняет код низкого уровня.С другой стороны, интерпретатор анализирует и выполняет исходный код напрямую. Интерпретатор обычно использует одну из нескольких техник:

  1. Анализирует (разбирает) исходный код и выполняет его напрямую.
  2. Преобразует исходный код высокого уровня в промежуточный код и немедленно выполняет его.
  3. Явно выполняет сохраненный предварительно скомпилированный код, созданный компилятором. В этом случае компилятор принадлежит системе интерпретатора.

Давайте посмотрим краткое сравнение интерпретатора и компилятора:

КОМПИЛЯТОР: ПЕРЕВОДЧИК:
1.Преобразует код, но не выполняет его. 1. Выполняет код напрямую.
2. Реализация компилятора требует знания целевой машины. 2. Нет необходимости в знаниях о целевой машине, так как интерпретатор выполняет код.
3. Каждая инструкция переводится только один раз. 3. Одна и та же инструкция может быть проанализирована несколько раз.
4. Скомпилированная программа запускается быстрее. 4. Интерпретируемые программы выполняются медленнее, но на их интерпретацию уходит меньше времени, чем на компиляцию и выполнение.
5. Потребляет больше памяти из-за промежуточной генерации кода. 5. Обычно выполняет входной код напрямую, поэтому потребляет меньше памяти.
6. Примеры скомпилированных языков: Java, C ++, Swift, C #. 6. Примеры интерпретируемых языков: Ruby, Lisp, PHP, PowerShell.

4. Примеры компилятора

4.1. Javac

В Java исходный код сначала компилируется в байт-код компилятором javac. Затем виртуальная машина Java (JVM) интерпретирует и выполняет байт-код. Итак, javac — отличный пример компилятора, принадлежащего системе интерпретатора. Такая система делает Java переносимой и многоплатформенной.

Кроме того, существуют другие языки, такие как Kotlin или Scala, которые также компилируются в байт-код, но используют уникальные компиляторы. Таким образом, JVM может выполнять код, изначально написанный с использованием различных технологий.

4.2. Моно

Mono — это набор инструментов, включая компилятор языка программирования C #, для выполнения программного обеспечения, предназначенного для платформы .NET. Он был создан для того, чтобы приложения .NET могли работать на разных платформах. Более того, важной целью было предоставить разработчикам, работающим над Linux, лучшую среду и инструменты для работы с платформой .NET.

Компилятор преобразует исходный код C # в промежуточный байт-код. После этого виртуальная машина выполнит его. И компилятор C #, и виртуальная машина принадлежат набору инструментов Mono.

4.3. Коллекция компиляторов GNU

Коллекция компиляторов GNU (GCC) — это набор компиляторов с открытым исходным кодом, принадлежащих проекту GNU. Эти компиляторы могут работать на разных аппаратных и программных платформах. Следовательно, они могут генерировать машинный код для различных архитектур и операционных систем.

Во время компиляции GCC отвечает за обработку аргументов, вызов компилятора для конкретного языка программирования, запуск программы ассемблера и, в конечном итоге, запуск компоновщика для создания исполняемого двоичного файла.

GCC состоит из компиляторов для нескольких языков программирования:

  • C (gcc)
  • C ++ (g ++)
  • Objective-C (gobjc)
  • Фортран (G77 и GFortran)
  • Java (gcj)
  • Ада (комар)

5. Заключение

В этой статье мы описали роль компилятора. Далее мы прошли все этапы процесса компиляции. Затем мы обсудили различия между компилятором и интерпретатором. Наконец, мы упомянули несколько реальных примеров компиляторов.

Язык программирования C ++ в хеминформатике и вычислительной химии | Journal of Cheminformatics

Давайте сначала обсудим основные функции C ++, которые он унаследовал от C и которые не связаны с такими продвинутыми концепциями, как объектно-ориентированное или универсальное программирование. Следует отметить, что современный C не является истинным подмножеством современного C ++, и современный компилятор C ++ не будет компилировать большинство нетривиальных программ, написанных на современном C, без хотя бы некоторых незначительных изменений. Однако для целей данной статьи мы можем рассматривать современный C ++ как расширение «классического C с большей безопасностью типов и без некоторых относительно редко используемых функций».В этом разделе для краткости C ++ будет означать «C или C ++».

C ++ — это в первую очередь компилируемый язык

Перед тем, как его можно будет выполнить, вся программа на C ++ должна быть «построена», то есть переведена в собственные инструкции целевой машины программой, называемой компилятором , и связана с внешними предварительными версиями. скомпилированные библиотеки программой под названием linker . Высококачественные компиляторы выполняют обширную локальную и глобальную оптимизацию кода и создают очень эффективный и компактный код.Скомпилированные программы не нуждаются в каких-либо дополнительных средах выполнения на целевых компьютерах для выполнения. Сравните это с интерпретируемыми языками, такими как Python, или языками, которые обычно компилируются и доставляются пользователям как платформенно-независимый промежуточный код, как и Java. Коду Python требуется интерпретатор Python для выполнения, а программам, скомпилированным в промежуточный байт-код Java, требуется среда выполнения Java для преобразования промежуточного кода в инструкции хост-машины во время выполнения.Для компиляции большой программы на C ++ может потребоваться значительное время, поскольку каждая строка ее исходного кода должна обрабатываться компилятором, независимо от того, будет ли она на самом деле выполняться во время вызова программы. Это замедляет цикл разработки, но обычно приводит к более надежному коду, поскольку компилятор может уловить множество ошибок во время компиляции, что позволяет избежать неприятных сюрпризов, связанных с «ошибками времени выполнения», столь типичных для интерпретируемых языков, таких как Python. Еще одним недостатком скомпилированного языка является то, что исполняемые файлы, созданные компилятором из исходного кода, не переносимы и будут работать только на целевой платформе (то есть на оборудовании плюс операционная система), для которой они скомпилированы, или в двоичном формате. -совместимая платформа.Следует проявлять особую осторожность при написании кода C ++, указании параметров компилятора и выборе библиотек кода для связывания, чтобы удовлетворить определенные требования двоичной совместимости (см., Например, статью в Википедии о двоичной совместимости [19] и Red Hat Enterprise Linux 7: Совместимость приложений Руководство [20] только для того, чтобы понять, насколько сложной может быть проблема двоичной совместимости). Чтобы перенести программу или библиотеку C ++ на другую платформу, исходный код необходимо перекомпилировать специально для этой платформы.Поскольку в настоящее время компиляторы C ++ существуют для всех основных компьютерных платформ и операционных систем, как правило, исходный код C ++ легко переносится. Однако сложные программы, написанные на C ++ с использованием нестандартных или плохо поддерживаемых языковых функций или имеющие зависимости от библиотек кода, которые не были широко перенесены, или полагающиеся на определенные функции машины или ОС, такие как, например, размер машинного слова, байты Порядок или поддержка определенных инструкций ЦП могут быть чрезвычайно сложными для переноса и могут потребовать внесения изменений на уровне кода опытным программистом на C ++.Существует очень полезный онлайн-инструмент под названием Compiler Explorer [21], который может компилировать фрагменты программ на многих языках программирования, включая C ++, с различными компиляторами и опциями в интерактивном режиме и визуализировать вывод машинного кода. Это делает его отличным обучающим инструментом, который также можно использовать для оптимизации кода низкого уровня.

Следует отметить, что стандарт языка C ++ не предписывает, что программа на C ++ должна быть сначала полностью скомпилирована в исполняемый файл, содержащий машинные инструкции целевой платформы, прежде чем она может быть запущена.Интерпретаторы C ++, которые позволяют выполнять код C ++ в интерпретируемом и / или интерактивном режиме построчно, действительно существуют (например, Cling [22]), но сама природа языка, в частности статическая типизация, делает не очень хорошо сочетаются с интерактивным режимом выполнения цикла чтения-оценки-печати (REFL), поэтому интерпретаторы C ++ остаются очень специализированными нишевыми инструментами для быстрого создания прототипов и разработки компиляторов.

C ++ является императивным

Императивное программирование — это парадигма программирования, в которой программа состоит из операторов (или команд для компьютера), которые изменяют состояние программы.Императивное программирование фокусируется на описании того, как работает программа, а императивный код точно соответствует машинному коду, встроенному в компьютер. На низком уровне состояние программы определяется содержимым памяти, а инструкции на собственном машинном языке компьютера предписывают аппаратному обеспечению, как изменять данные в памяти. Императивные языки более высокого уровня абстрагируются от специфичных для платформы инструкций, например, используют переменные вместо ячеек памяти и операторов, написанных в удобочитаемой нотации, а не кодами инструкций, но все же следуют тому же шаблону.

Сравните императив с декларативной парадигмой, которая фокусируется на том, каким должен быть желаемый результат, и оставляет на усмотрение механизма выполнения «решать», как его получить. Распространенным декларативным языком, знакомым большинству специалистов по данным, является SQL (язык структурированных запросов), который предназначен для управления данными, хранящимися в системе реляционной базы данных, такой как Oracle или PostgreSQL. Например, типичный оператор запроса данных SQL «выберите A, B, C из таблицы1, соедините таблицу 2 с таблицей 1.K = Table2.FK» описывает , какие записи из каких таблиц в реляционной базе данных нужно извлечь, но не инструктирует базу данных Engine, как это сделать, и реализации процессоров запросов SQL могут сильно различаться в разных механизмах базы данных.

C ++ — процедурный

Язык процедурного программирования — это императивный язык программирования, который поддерживает концепцию процедур и подпрограмм, разделяющих сегменты кода на повторно используемые блоки, которые можно «вызывать» для выполнения отдельных задач. Процедуры и подпрограммы известны как функции , в C или C ++. Функция C ++ может принимать ноль или более параметров (иногда называемых аргументами) и возвращать ноль или одно значение.

C ++ поддерживает структурированное программирование

Структурированные языки программирования предоставляют интуитивно понятные механизмы для управления потоком программы (то есть порядком, в котором выполняются операторы).Операторы управления структурированным потоком в C ++ аналогичны операторам многих других языков структурированного программирования. Это if / else для реализации логики ветвления и для , , в то время как и do / while для реализации итераций (циклов). В C ++ есть пресловутый оператор goto , который можно использовать для передачи управления в произвольное место внутри функции «неструктурированным» способом, но он используется редко.

C ++ имеет лексическую область видимости переменных

Как и большинство современных языков, C ++ использует лексическую область видимости для переменных и функций.На переменную или функцию в C ++ можно ссылаться только из блока кода, в котором они объявлены. Объем определяется при компиляции кода. В противоположность лексической области видимости, динамическая область видимости относится к области видимости переменной, определенной во время выполнения и зависящей от состояния программы, когда встречается имя переменной.

C ++ статически типизирован, но не типобезопасен

Компилятор выполняет проверку типа при компиляции программы C ++. Это помогает обнаруживать распространенные ошибки программирования.В языках с динамической типизацией (таких как, например, Python или JavaScript) типы переменных и функций проверяются во время выполнения, что обеспечивает дополнительную гибкость и иногда сокращает код, но часто приводит к ошибкам времени выполнения, когда операция или функция применяется к объекту несоответствующего типа. Следует отметить, что C ++ не является типобезопасным языком. Компиляторы C ++ допускают множество операций с типизированными переменными, которые могут привести к неопределенному поведению или ошибкам, но обычно программист должен «сообщить компилятору» о своем намерении, например, путем «приведения» указателя на ячейку памяти к определенному тип.Это очень удобно в низкоуровневом программировании, где эффективный доступ к оборудованию является обязательным, но программисты должны знать, что они делают, поскольку ошибки, возникающие из-за небезопасных преобразований типов, как известно, трудно отлаживать и часто зависят от платформы.

C ++ имеет средства для низкоуровневого манипулирования памятью

C ++ предоставляет операции с указателями на произвольные ячейки памяти, что делает C ++ идеальным выбором для программирования операционных систем, встроенных систем и драйверов устройств.Например, драйвер периферийного устройства ввода / вывода может отображать (или связывать) память и регистры управляемого устройства с определенными зарезервированными адресами [12]. Чтобы управлять устройством, драйвер устройства назначает значения, имеющие особое значение в соответствии со спецификациями устройства, этим зарезервированным ячейкам памяти. Например, следующий оператор в коде драйвера (при условии, что он реализован на C или C ++) устанавливает для байта в ячейке памяти 40008000 (в шестнадцатеричном представлении) значение 1.

Тип данных char в C / C ++ — это наименьшая адресуемая единица машины (на большинстве современных компьютеров один байт состоит из восьми бит).(Char *) — это оператор приведения типа , сообщающий компилятору интерпретировать 0x40008000 как указатель на байт в ячейке памяти 0x40008000, а префикс * (символ звездочки) — это указатель , разыменовывающий оператор , используемый для доступа к ( чтение или запись) значение, хранящееся в этом месте.

Манипулирование данными с помощью указателей памяти в C ++ — очень распространенная практика не только в низкоуровневом системном программировании, но и при реализации широкого спектра алгоритмов и структур данных с минимально возможными накладными расходами.Общие структуры данных векторного типа, такие как векторы, матрицы и символьные строки, эффективно представлены в C ++ непрерывными блоками памяти, содержащими данные определенного типа, а C ++ предоставляет очень сжатый синтаксис для операций с этими блоками памяти. Например, определение позиции символа в строке C с нулевым завершением с использованием операций с указателем C может быть выполнено с помощью всего одной строки кода, цикла и в фрагменте кода, показанном ниже:

C ++ имеет детерминированное распределение памяти и de-allocation

Время жизни объектов в C ++ детерминировано и определяется программистом.Это устраняет накладные расходы на «сборку мусора», когда среда выполнения (такая как, например, виртуальная машина Java или интерпретатор Python) должна отслеживать время жизни объектов во время выполнения программы и, когда объект больше не используется, освобождать увеличить ресурсы, связанные с ним [23]. Это также позволяет разместить объект по указанному адресу памяти. Это делает C и C ++ особенно подходящими для написания кода для систем с ограниченными ресурсами, таких как системы реального времени и микроконтроллеры.Ниже приведен пример, иллюстрирующий детерминированное управление памятью C / C ++ кучей и стеком [24]:

Максимальная эффективность C ++, достигаемая за счет прямого доступа к памяти через указатели, явного детерминированного управления памятью и очень близкого сопоставления языковых конструкций C ++ с аппаратным обеспечением. C ++ — язык выбора в высокопроизводительных научных вычислениях при реализации алгоритмов, интенсивно использующих процессор и память, например, для моделирования молекулярной механики, машинного обучения и статистического анализа очень больших объемов данных.Однако за эффективность приходится платить. Ошибки программиста, такие как доступ к массиву за пределами границ или забывание должным образом инициализировать указатель, приводят к случайным сбоям программы или неожиданному поведению, которое в сложном коде может быть чрезвычайно сложно обнаружить и исправить. Преднамеренный (для эффективности) или непреднамеренный пропуск проверок на общие ошибки ручного управления памятью, такие как переполнение буфера, в коде C или C ++ — это уязвимость системы безопасности, которая часто используется компьютерными вирусами, программами-вымогателями и другими типами вредоносных программ [25].Существует множество статических и динамических анализаторов и отладчиков кода, которые помогают программистам обнаруживать ошибки управления памятью в коде C ++, такие как, например, отладчик GDB [26] и инструментарий Valgrind [27]. Тем не менее, даже с помощью самых сложных компиляторов C ++ и средств разработки ошибок управления памятью в нетривиальном коде C и C ++ трудно избежать даже опытным программистам. Как было упомянуто выше, многие языки высокого уровня, такие как Python или Java, обеспечивают автоматическое управление памятью с «сборкой мусора» и запрещают или ограничивают прямой доступ к памяти через указатели, тем самым полностью устраняя возможность ошибок ручного управления памятью.Однако автоматическое управление памятью существенно снижает производительность и делает эти языки непригодными для низкоуровневого программирования.

C ++ — это язык высокого уровня с низкоуровневой функциональностью

C ++ предлагает программистам широкие возможности для выражения своих идей на высоком или низком уровне абстракции, в зависимости от конкретной задачи. C ++ (особенно его подмножество C) имеет очень небольшие накладные расходы времени выполнения и, как уже упоминалось выше, использует детерминированное явное выделение / освобождение памяти.При желании программа на C ++ может быть написана в минималистичном стиле «переносимого ассемблера» для эффективного управления оборудованием, например, при программировании драйверов устройств. В то же время C ++ позволяет кодировать в терминах абстрактных концепций информатики, таких как функции, типы и операторы, определяемые программистом, универсальные типы, лямбда-выражения и замыкания, что делает его подходящим для реализации сложных алгоритмов с нетривиальным потоком выполнения. логика, например, графические пользовательские интерфейсы и компиляторы.В научном программировании C ++ часто используется как объектно-ориентированный язык высокого уровня, в полной мере использующий его выразительные возможности. Высокоуровневые возможности C ++ будут описаны более подробно ниже в разделах этой статьи, посвященных объектно-ориентированному и универсальному программированию.

C ++ имеет препроцессор, который добавляет некоторые возможности метапрограммирования к языку.

Перед передачей компилятору код C ++ предварительно обрабатывается для расширения так называемых директив препроцессора.Наиболее распространенными директивами в C ++ являются расширяемые макросы, директивы включения файлов и условной компиляции. Их подробное описание выходит за рамки данной статьи, но заинтересованный читатель найдет несколько примеров директив предварительной обработки в приведенном ниже коде Hello, World . Их можно идентифицировать в источнике по символу # (решетка), который отмечает начало директивы.

Hello, World in C

Прежде чем мы обратимся к более сложным концепциям, связанным с объектно-ориентированным и универсальным программированием на C ++, давайте рассмотрим рабочий пример простой программы, которая демонстрирует «подмножество C» C ++.Код ниже показывает слегка расширенную и прокомментированную версию традиционного «Hello, World!» программа, которую можно запустить из командной строки, чтобы отобразить «Hello, World!» или «Привет, < кто-то >», в зависимости от аргументов командной строки, с которыми он вызывается. Обратите внимание на директиву #include < filename >, которая включает содержимое файла заголовка , идентифицированного именем filename , в текущий исходный файл.

Программа также иллюстрирует типичный шаблон выполнения компиляции / компоновки / запуска программы C ++.Чтобы создать исполняемый файл из приведенного выше исходного кода, нужно скомпилировать его в промежуточный модуль и связать модуль со стандартными и пользовательскими библиотеками, которые содержат предварительно созданные реализации функций, используемых в исходном коде, но не определенных. там. Приведенный выше пример очень прост и зависит только от стандартной библиотеки времени выполнения C для процедур инициализации программы и реализации функции printf , поэтому его можно скомпилировать и связать для создания исполняемого файла в большинстве современных Unix-подобных систем (Linux , Mac OS X, FreeBSD, AIX и другие) с помощью очень простой команды:

При запуске с указанными выше параметрами командной строки компилятор вызовет компоновщик и автоматически свяжет стандартные библиотеки времени выполнения C для создания исполняемого модуля.Все современные Unix-подобные системы поставляются с компилятором C / C ++, но, в зависимости от конкретной версии и дистрибутива ОС, вам, возможно, придется заменить gcc на cc, C ++ или g ++. Если компилятор обнаружит одну или несколько синтаксических ошибок в исходном коде во время компиляции, он сообщит о них программисту и не создаст исполняемый файл. Запуск полученного исполняемого файла из командной строки приведет к выводу «Hello, World!» или «Привет, аргумент !».

Следует еще раз отметить, что скомпилированный исполняемый файл содержит машинный код для целевой платформы, и не нуждается в интерпретаторе или среде выполнения для запуска .Однако он зависит от платформы и не будет работать на оборудовании и операционной системе, кроме той, для которой он был создан, или его эмулятора. Это контрастирует с интерпретируемыми языками, такими как Python, где интерпретатор переводит исходный код программы в машинные инструкции во время выполнения и немедленно выполняет эти инструкции. Программы на многих языках, включая C или C ++, могут быть либо скомпилированы, либо интерпретированы, поэтому «компилирование» или «интерпретация» не является существенным свойством языка как такового.Однако подавляющее большинство реализаций C и C ++ являются компиляторами, а не интерпретаторами. Структура C / C ++, в первую очередь статическая типизация, делает его использование в качестве интерпретируемого языка довольно громоздким и не реализует весь его потенциал как языка для системного программирования и высокопроизводительных вычислений.