close
Пространства имён
Варианты
Действия

Этапы трансляции

Материал из cppreference.com

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

Этап 1

1) Отдельные байты исходного файла (который обычно является текстовым файлом в некоторой многобайтовой кодировке, такой как UTF-8) отображаются определённым реализацией способом в символы набора исходных символов. В частности, зависящие от ОС индикаторы конца строки заменяются символами новой строки.
Набор исходных символов - это многобайтовый набор символов, который включает в себя основной набор исходных символов как однобайтовое подмножество, состоящее из следующих 96 символов:
а) 5 пробельных символов (пробел, горизонтальная табуляция, вертикальная табуляция, подача страницы, новая строка)
б) 10 символов цифр от '0' до '9'
в) 52 буквы от 'a' до 'z' и от 'A' до 'Z'
г) 29 символов пунктуации: _ { } [ ] # ( ) < > % : ; . ? * + - / ^ & | ~ ! = , \ " '
2) Последовательности триграфов заменяются соответствующими односимвольными представлениями. (до C23)

Этап 2

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

Этап 3

1) Исходный файл разбивается на комментарии, последовательности пробельных символов (пробел, горизонтальная табуляция, новая строка, вертикальная табуляция и подача страницы), и следующие токены предобработки, которые представлены ниже.
а) названия заголовочных файлов: <stdio.h> или "myfile.h"
в) предобрабатываемые числа, которые включают в себя целочисленные константы и константы с плавающей запятой, а также охватывают некоторые недопустимые токены, такие как 1..E+3.foo или 0JBK
д) операторы и пунктуаторы, такие как +, <<=, <% или ##.
е) отдельные непробельные символы, которые не попадают ни в одну другую категорию
2) Каждый комментарий заменяется одним символом пробела
3) Новые строки сохраняются, и это определяется реализацией, могут ли последовательности пробельных символов, не являющиеся символами новой строки, быть заменены на один символ пробела.

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

int foo = 1;
int bar = 0xE+foo;   // ошибка: неверное предобрабатываемое число 0xE+foo
int baz = 0xE + foo; // OK
int pub = bar+++baz;   // OK: bar++ + baz
int ham = bar++-++baz; // OK: bar++ - ++baz
int qux = bar+++++baz; // ошибка: bar++ ++ +baz, не bar++ + ++baz.

Единственным исключением из правила максимального выбора является:

  • Препроцессорные токены предобработки имени заголовочного файла формируются только в директиве #include и в местах, определяемых реализацией, в директиве #pragma.
#define MACRO_1 1
#define MACRO_2 2
#define MACRO_3 3
#define MACRO_EXPR (MACRO_1 <MACRO_2> MACRO_3) // OK: <MACRO_2> не является именем заголовочного файла

Этап 4

1) Запускается препроцессор.
2) Каждый файл, введенный с помощью директивы #include, проходит этапы с 1 по 4 рекурсивно.
3) В конце данного этапа все директивы препроцессора удаляются из исходного кода.

Этап 5

1) Все символы и управляющие последовательности в символьных константах и строковых литералах преобразуются из набора исходных символов в набор выполнимых символов (который может быть многобайтовым набором символов, таким как UTF-8, при условии, что все 96 символов из основного набора исходных символов, перечисленные в этапе 1, имеют однобайтовое представление). Если символ, указанный управляющей последовательностью, не является членом набора выполнимых символов, результат определяется реализацией, но гарантируется, что это будет не нулевой (широкий) символ.

Примечание: преобразование, выполняемое на данном этап, может управляться параметрами командной строки в некоторых реализациях: gcc и clang используют -finput-charset для указания кодировки набора исходных символов, -fexec-charset и -fwide-exec-charset для указания кодировки набора выполнимых символов в строковых литералах и символьных константах, которые не имеют кодирующий префикс (начиная с C11).

Этап 6

Соседние строковые литералы объединяются.

Этап 7

Происходит компиляция: токены анализируются синтаксически и семантически и транслируются как единицы трансляции.

Этап 8

Происходит компоновка: единицы трансляции и компоненты библиотек, необходимые для разрешения внешних ссылок, собираются в образ программы, который содержит информацию, необходимую для выполнения в её среде выполнения (ОС).

Ссылки

  • Стандарт C17 (ISO/IEC 9899:2018):
  • 5.1.1.2 Translation phases (стр. 9-10)
  • 5.2.1 Character sets (стр. 17)
  • 6.4 Lexical elements (стр. 41-54)
  • Стандарт C11 (ISO/IEC 9899:2011):
  • 5.1.1.2 Translation phases (стр. 10-11)
  • 5.2.1 Character sets (стр. 22-24)
  • 6.4 Lexical elements (стр. 57-75)
  • Стандарт C99 (ISO/IEC 9899:1999):
  • 5.1.1.2 Translation phases (стр. 9-10)
  • 5.2.1 Character sets (стр. 17-19)
  • 6.4 Lexical elements (стр. 49-66)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
  • 2.1.1.2 Translation phases
  • 2.2.1 Character sets
  • 3.1 Lexical elements

См. также

Документация C++ по Этапы трансляции