Фазы трансляции
Файл исходного кода C++ обрабатывается компилятором как будто выполняются следующие фазы в точном порядке:
Фаза 1
1) Отдельные байты файла исходного кода отображаются (по определению реализации) на символы основного набора символов исходного текста. В частности, зависящие от ОС маркеры конца строки заменяются символами новой строки. 2) Набор символов исходного файла, которые принимаются, определяется реализацией(с C++11). Любой символ исходного файла, который не может быть отображён на символ основного набора символов исходного текста, заменяется его универсальным именем символа (с экранированием \u или \U) или некоторым определённым реализацией способом, который обрабатывается эквивалентно.
| (до C++23) | ||
| Файлы-входы, являющиеся последовательностью единиц кодировки UTF-8 (файлы UTF-8), гарантированно поддерживаются. Набор других типов поддерживаемых файлов-входов определяется реализацией. Если набор не пуст, тип файла-входа определяется реализацией определённым способом, который включает способ обозначения файлов-входов как файлов UTF-8, независимо от их содержимого (распознавание маркера порядка байтов недостаточно).
| (с C++23) |
Фаза 2
Фаза 3
<iostream> или "myfile.h"
b) маркеры-заполнители, созданные предпроцессором директивами импорта и модулей (т.е. import XXX; и module XXX;) | (с C++20) |
- апостроф (
', U+0027), - кавычка (
", U+0022), или - символ, не входящий в основной набор символов.
| 2) Любые преобразования, выполненные во время фазе 1 и(до C++23) фазе 2 между начальной и конечной двойной кавычкой любого сырого строкового литерала отменяются. | (с C++11) |
Символы новой строки сохраняются, и не определено, могут ли не являющиеся символами новой строки последовательности пробелов быть объединены в один символ пробела.
| Когда символы из файла исходного кода потребляются для формирования следующего предпроцессорного токена (то есть не потребляемого как часть комментария или других форм пробелов), универсальные имена символов распознаются и заменяются указанным элементом набора символов трансляции, кроме случаев соответствия последовательности символов в: a) символьном литерале (c-char-sequence) b) строковом литерале (s-char-sequence и r-char-sequence), исключая разделители (d-char-sequence) c) имени файла для включения (h-char-sequence и q-char-sequence) | (с C++23) |
Если вход был проанализирован в предпроцессорные токены до данного символа, то следующий предпроцессорный токен, как правило, принимается как самая длинная последовательность символов, которая может составлять предпроцессорный токен, даже если это приведёт к тому, что последующий анализ потерпит неудачу. Это обычно называется максимальным разбором.
int foo = 1; int bar = 0xE+foo; // error, invalid preprocessing number 0xE+foo int baz = 0xE + foo; // OK int quux = bar+++++baz; // error: bar++ ++ +baz, not bar++ + ++baz.
Единственными исключениями из правила максимального разбора являются:
#define R "x" const char* s = R"y"; // ill-formed raw string literal, not "x" "y" const char* s2 = R"(a)" "b)"; // a raw string literal followed by a normal string literal
struct Foo { static const int v = 1; };
std::vector<::Foo> x; // OK, <: not taken as the alternative token for [
extern int y<::>; // OK, same as extern int y[].
int z<:::Foo::value:>; // OK, int z[::Foo::value]; | (с C++11) |
- Токены имени заголовочного файла образуются только внутри
#includeилиimport(с C++20) директивы или в__has_includeвыражении(с C++17).
std::vector<int> x; // OK, <int> not a header-name
Фаза 4
#include директивы, проходит через фазы 1 до 4 рекурсивно.Фаза 5
| 1) Все символы в литералах символов и литералах строк преобразуются из исходной кодовой страницы в кодировку (которая может быть многобайтовой кодировкой, такой как UTF-8, при условии, что 96 символов базового набора символов имеют однобайтовые представления). 2) Экранированные последовательности и универсальные имена символов в литералах символов и несырых строковых литералах расширяются и преобразуются в литеральную кодировку. Если символ, указанный универсальным именем символа, не может быть закодирован как один код в соответствующей литеральной кодировке, результат определяется реализацией, но гарантируется, что он не будет нулевым (широким) символом. Примечание: преобразование, выполняемое на этом этапе, может контролироваться параметрами командной строки в некоторых реализациях: gcc и clang используют | (до C++23) |
| Для последовательности двух или более смежных строковых литералов общий префикс кодировки определяется, как описано здесь. Каждый такой строковый литерал затем рассматривается как имеющий этот общий префикс кодировки. (Преобразование символов перенесено на этап 3) | (с C++23) |
Этап 6
Смежные строковые литералы конкатенируются.
Этап 7
Происходит компиляция: каждый предварительный токен преобразуется в токен. Токены синтаксически и семантически анализируются и переводятся как единица трансляции.
Этап 8
Каждая единица трансляции исследуется для создания списка требуемых экземплярий шаблонов, включая запрошенные явными экземплярами. Определения шаблонов находятся, и требуемые экземпляры выполняются для получения единиц экземплярования.
Этап 9
Единицы трансляции, единицы экземплярования и библиотечные компоненты, необходимые для удовлетворения внешних ссылок, собираются в образ программы, который содержит информацию, необходимую для выполнения в его среде выполнения.
Примечания
Некоторые компиляторы не реализуют единицы экземплярования (также известные как хранилища шаблонов или реестры шаблонов) и просто компилируют каждый экземпляр шаблона на этапе 7, сохраняя код в объектном файле, где он неявно или явно запрашивается, а затем компоновщик объединяет эти скомпилированные экземпляры в один на этапе 9.
Отчеты об ошибках
Следующие отчеты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение, как опубликовано | Корректное поведение |
|---|---|---|---|
| CWG 787 | C++98 | поведение было неопределенным, если непустой исходный файл не заканчивается символом новой строки в конце этапа 2 | добавление завершающего символа новой строки в этом случае |
| CWG 1775 | C++11 | формирование универсального имени символа внутри несырого строкового литерала на этапе 2 приводило к неопределенному поведению | сделано определённым |
| P2621R2 | C++98 | универсальные имена символов не разрешались для формирования с помощью слияния строк или конкатенации токенов | разрешено |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2023):
- 5.2 Фазы трансляции [lex.phases]
- Стандарт C++20 (ISO/IEC 14882:2020):
- 5.2 Фазы трансляции [lex.phases]
- Стандарт C++17 (ISO/IEC 14882:2017):
- 5.2 Фазы трансляции [lex.phases]
- Стандарт C++14 (ISO/IEC 14882:2014):
- 2.2 Фазы трансляции [lex.phases]
- Стандарт C++11 (ISO/IEC 14882:2011):
- 2.2 Фазы трансляции [lex.phases]
- Стандарт C++03 (ISO/IEC 14882:2003):
- 2.1 Фазы трансляции [lex.phases]
- Стандарт C++98 (ISO/IEC 14882:1998):
- 2.1 Фазы трансляции [lex.phases]
См. также
| C документация для Фазы трансляции |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/translation_phases