Каковы этапы компиляции программы на C ++? - PullRequest
24 голосов
/ 12 января 2012

Стадии компиляции программы на C ++ определены стандартом?

Если так, то что они?

Если нет, то ответ для широко используемого компилятора (я бы предпочел MSVS) было бы здорово.

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

РЕДАКТИРОВАТЬ: я знаю, что делают компиляция, компоновка и предварительная обработка, меня больше всего интересуют другие и порядок. Разъяснения к ним, конечно, также приветствуются, поскольку я, возможно, не единственный, кто заинтересован в ответе.

Ответы [ 3 ]

38 голосов
/ 12 января 2012

Стадии компиляции программы на C ++ определены стандартом?

Да и нет.

Стандарт C ++ определяет 9 "фаз перевода".Цитата из черновика N3242 (10 МБ PDF) от 2011-02-28 (до выпуска официального стандарта C ++ 11), раздел 2.2:

Приоритет среди синтаксических правил перевода определяется следующими этапами [см. сноску] .

  1. Физические символы исходного файла отображаются в соответствии с реализацией в основныеисходный набор символов (ввод символов новой строки для индикаторов конца строки) при необходимости. [SNIP]
  2. Каждый экземпляр символа обратной косой черты (\), за которым сразу следует символ новой строки, удаляется, объединяя физические исходные строки для формирования логических исходных строк. [SNIP]
  3. Исходный файл разбит на токены предварительной обработки (2.5) и последовательности символов пробела (включая комментарии). [SNIP]
  4. Выполняются директивы предварительной обработки, расширяются вызовы макросов и выполняются выражения унарного оператора _Pragma. [SNIP]
  5. Каждый элемент исходного набора символов в символьном литерале или строковом литерале, а также каждая escape-последовательность и универсальное имя-символа в символьном литерале или не-сыройстроковый литерал, преобразуется в соответствующий член набора символов выполнения; [SNIP]
  6. Литеральные токены смежных строк объединяются.
  7. Пробельные символы, разделяющие токены, больше не имеют значения.Каждый токен предварительной обработки преобразуется в токен.(2.7).Полученные токены синтаксически и семантически анализируются и переводятся как единица перевода. [SNIP]
  8. Переведенные единицы перевода и единицы создания экземпляров объединяются следующим образом: [SNIP]
  9. Все ссылки на внешние объекты разрешены.Компоненты библиотеки связаны для удовлетворения внешних ссылок на объекты, не определенные в текущем переводе.Все такие выходные данные транслятора собираются в образ программы, который содержит информацию, необходимую для выполнения в среде выполнения.

[сноска] Реализации должны вести себя так, как если бы эти отдельные фазы происходили, хотяна практике разные фазы могут быть сложены вместе.

Как указано маркерами [SNIP] , я не процитировал весь раздел, просто достаточно, чтобы понять идею.

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

Фазы 1-6 соответствуют более илименьше для препроцессора, 7 для того, что вы обычно можете рассматривать как компиляцию, 8 имеет дело с шаблонами, а 9 соответствует связыванию.

(фазы перевода C аналогичны, но # 8 опущен.)

6 голосов
/ 12 января 2012

9 так называемых «фаз перевода» перечислены в стандарте в [lex.phases] (2.2 в C ++ 11, 2.1 в C ++ 03).

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

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

Он также не дает никакой детализации при разборе, он просто говорит: "Полученные токены синтаксически синтаксическии семантически проанализированы и переведены ».Это связано с тем, что для полноты этой детали требуются главы 3-15.

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

3 голосов
/ 12 января 2012

Спецификация C ++ преднамеренно расплывчата во многих отношениях, главным образом, чтобы оставаться независимой от реализации. Многие области, в которых язык расплывчатый, больше не представляют большой проблемы - например, вы обычно можете полагаться на 8-битный символ. Тем не менее, другие вопросы, такие как расположение структур, которые используют множественное наследование, представляют реальную проблему, как и влияние виртуальных функций на классы. Эти проблемы влияют на совместимость кода, созданного различными компиляторами. Двоичный интерфейс приложения (или ABI) C ++ не является строго определенным, и в результате вам иногда приходится заглядывать в C, где это становится проблематичным. Написание интерфейса плагина является хорошим примером.

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

Я кратко посмотрел, довольно сложно найти описания отдельных компиляторов. Я сомневаюсь, что есть много коммерческих компиляторов, таких как предложения Microsoft, исключительно по коммерческим причинам. GCC - ваш лучший выбор, , хотя Microsoft с радостью описывает этот процесс. Хотя это довольно банальная вещь: все компиляторы работают примерно одинаково. Настоящее золото в том, как они выполняют эти этапы, алгоритмы и структуры данных, которые они используют. В этом отношении Я рекомендую эту книгу . Я купил совершенно новый экземпляр для университетского курса несколько лет назад, и я позаимствовал большинство своих учебников из библиотеки:).

...