Фазы трансляции
Исходный файл C++ должен быть препроцессирован компилятором так, как будто последовательно выполняются следующие фазы:
Содержание |
[править] Фаза 1
\u или \U) или какой-либо формой, определяемой реализацией, которая обрабатывается эквивалентно. (до C++23)|
3) Триграфы заменяются соответствующими односимвольными представлениями.
|
(до C++17) |
[править] Фаза 2
[править] Фаза 3
|
2) Отменяются любые преобразования, выполненные во время фаз 1 и 2 между символами " (открывающая и закрывающая двойная кавычка), в любом необработанном строковом литерале.
|
(начиная с C++11) (до C++23) |
|
2) Любые преобразования, выполненные во время фазы 2 (объединение строк) между начальной и конечной двойной кавычкой любого сырого строкового литерала, отменяются.
|
(начиная с C++23) |
Новые строки сохраняются, и не указано, могут ли последовательности пробельных символов, не являющихся символами новой строки, быть свёрнуты в одиночные пробелы.
|
Поскольку символы из исходного файла используются для формирования следующего токена предварительной обработки (т.е. не используются как часть комментария или других форм пробелов), универсальные имена символов распознаются и заменяются указанным элементом набора символов перевода, за исключением случаев соответствия последовательности символов в: b) строковый литерал (символьная-последовательность-s и символьная-последовательность-r), исключая разделители (символьная-последовательность-d)
|
(начиная с C++23) |
Если последовательность входных символов синтаксическим разбором была преобразована в лексемы препроцессора вплоть до данного символа, следующей лексемой препроцессора обычно будет последовательность символов максимальной длины, из которой можно сформировать лексему, даже если последующий анализ закончится неудачей. Данный подход известен как правило максимальной длины (maximal munch).
int foo = 1; int bar = 0xE+foo; // ошибка, недействительное число препроцессора 0xE+foo int baz = 0xE + foo; // OK int quux = bar+++++baz; // ошибка: распознается как bar++ ++ +baz, а не как bar++ + ++baz.
Исключения из правила максимального куска:
#define R "x" const char* s = R"y"; // некорректный необработанный строковый литерал, // не "x" "y" const char* s2 = R"(a)" "b)"; // необработанный строковый литерал, // за которым идёт обычный строковый литерал
struct Foo { static const int v = 1; }; std::vector<::Foo> x; // OK, <: не рассматривается как альтернативная лексема для [ extern int y<::>; // OK, эксивалентно extern int y[]. int z<:::Foo::value:>; // OK, int z[::Foo::value]; |
(начиная с C++11) |
- Лексемы препроцессора, указывающие имена заголовочных файлов, формируются только внутри директивы
#include.
std::vector<int> x; // OK, <int> не имя заголовочного файла
[править] Фаза 4
[править] Фаза 5
Примечание: преобразование, выполняемое на этом этапе, в некоторых реализациях может управляться параметрами командной строки : GCC и Clang используют -finput-charset и -fwide-exec-charset для указания соответственно кодировок исходного и исполняемого набора символов в строковых и символьных литералах , которые не имеют префикса, указывающего кодировку (начиная с C++11). Visual Studio, начиная с Visual Studio 2015 Обновление 2, использует параметры /source-charset и /execution-charset соответственно.
[править] Фаза 6
Смежные строковые литералы объединяются.
[править] Фаза 7
Выполняется компиляция: каждая лексема препроцессора преобразуется в лексему. Эти лексемы анализируются синтаксически и семантически, а затем преобразуются как единицы трансляции.
[править] Фаза 8
Каждая единица трансляции проверяется, чтобы создать список необходимых экземпляров шаблонов, включая те, что требуют явного создания. Находятся определения шаблонов и требуемые инстанцирования выполняются для создания экземпляров единиц.
[править] Фаза 9
Единицы трансляции, единицы инстанцирования и компоненты библиотек, необходимые для удовлетворения внешних ссылок, собираются в образ программы, который содержит информацию, необходимую для выполнения в ее среде выполнения.
[править] Примечания
Некоторые компиляторы не реализуют единицы инстанцирования (также известных как репозитории шаблонов или шаблонные регистры) и просто компилируют каждое инстанцирование шаблона в фазе 7, сохраняя код в объектный файл, откуда он явно или неявно запрашивается, а затем компоновщик на этапе 9 сворачивает эти скомпилированные инстанцирования в одно.
[править] Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| CWG 787 | C++98 | поведение было неопределённым, если непустой исходный файл не заканчивался символом новой строки в конце фазы 2 |
в этом случае добавляется завершающий символ новой строки |
| CWG 1775 | C++11 | формирование универсального имени символа внутри необработанного строкового литерала на этапе 2 приводило к неопределённому поведению |
чётко определено |
[править] Ссылки
- 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 для Фазы трансляции
|

