1.2 Инициализация обработки
Препроцессор выполняет серию текстовых преобразований входного файла. Эти преобразования выполняются до всех остальных процессов. Концептуально они выполняются в строгом порядке, и весь файл проходит через каждое преобразование, прежде чем начнётся следующее. Компилятор CPP фактически выполняет все преобразования одновременно по причинам производительности. Эти преобразования примерно соответствуют трём «фазам трансляции», описанным в стандарте C.
- Вводной файл считывается в память и разбивается на строки.
Разные системы используют разные соглашения для обозначения конца строки. GCC принимает ASCII управляющие последовательности LF, CR LF и CR в качестве маркеров конца строки. Это стандартные последовательности, используемые в Unix, DOS и VMS, а также в классической Mac OS (до OSX) соответственно. Поэтому вы можете без проблем копировать исходный код, написанный в любой из этих систем, в другую и использовать его без преобразования. (GCC может потерять отслеживание текущего номера строки, если файл не использует последовательно одну конвенцию, как это иногда происходит, когда он редактируется на компьютерах с различными конвенциями, которые используют общую файловую систему в сети.)
Если последняя строка любого входного файла не содержит маркер конца строки, конец файла неявно считается содержащим его. Стандарт C указывает, что это условие вызывает неопределённое поведение, поэтому GCC выведет сообщение об ошибке.
- Если включены триграфы, они заменяются соответствующими одиночными символами. По умолчанию GCC игнорирует триграфы, но если вы запрашиваете строгое соответствие с опцией -std или опцией -trigraphs, то он преобразует их.
Это девять трёхсимвольных последовательностей, все начинающиеся с ‘??’, которые по ISO C определены как стоящие для одиночных символов. Они позволяют устаревшим системам, которым не хватает некоторых знаков препинания языка C, использовать его. Например, ‘??/’ обозначает ‘\’, поэтому '??/n' — это символьная константа для новой строки.
Триграфы не пользуются популярностью, и многие компиляторы реализуют их неправильно. Переносимый код не должен полагаться на преобразование или игнорирование триграфов. С опцией -Wtrigraphs GCC предупредит вас, если триграф может изменить значение вашей программы при его преобразовании. Смотрите Wtrigraphs.
В строковой константе вы можете предотвратить, чтобы последовательность вопросительных знаков была воспринята как триграф, вставив обратную косую черту между вопросительными знаками или разделив строковый литерал на триграф и используя конкатенацию строковых литералов. "(??\?)" — это строка ‘(???)’, а не ‘(?]’. Традиционные компиляторы C не распознают эти выражения.
Девять триграфов и их замены:
Trigraph: ??( ??) ??< ??> ??= ??/ ??' ??! ??- Replacement: [ ] { } # \ ^ | ~ - Продолжающиеся строки объединяются в одну длинную строку.
Продолжающаяся строка — это строка, которая заканчивается обратной косой чертой, ‘\’. Обратная косая черта удаляется, а следующая строка присоединяется к текущей. Пробелы не вставляются, поэтому вы можете разделить строку где угодно, даже посередине слова. (Обычно более читабельно разделять строки только в местах пробелов.)
Конечная обратная косая черта в продолжении строки обычно называется backslash-newline.
Если между обратной косой чертой и концом строки есть пробелы, это всё ещё продолжающаяся строка. Однако, поскольку это обычно результат ошибки редактирования, и многие компиляторы не примут это как продолжение строки, GCC выведет об этом предупреждение.
- Все комментарии заменяются на одиночные пробелы.
Существует два типа комментариев. Блочные комментарии начинаются с ‘/*’ и продолжаются до следующего ‘*/’. Блочные комментарии не вложены:
/* this is /* one comment */ text outside comment
Строчные комментарии начинаются с ‘//’ и продолжаются до конца текущей строки. Строчные комментарии также не вложены, но это не имеет значения, потому что они всё равно заканчиваются в том же месте.
// this is // one comment text outside comment
Безопасно помещать строчные комментарии внутри блочных комментариев или наоборот.
/* block comment // contains line comment yet more comment */ outside comment // line comment /* contains block comment */
Но будьте осторожны при комментировании одного конца блочного комментария строчным комментарием.
// l.c. /* block comment begins oops! this isn’t a comment anymore */
Комментарии не распознаются внутри строковых литералов. "/* blah */" — это строковая константа ‘/* blah */’, а не пустая строка.
Строчные комментарии не присутствовали в издании стандарта C 1989, но GCC их распознаёт как расширение. В C++ и в издании стандарта C 1999 они являются официальной частью языка.
Поскольку эти преобразования происходят до всех других процессов, вы можете механически разделить строку с помощью backslash-newline где угодно. Вы можете прокомментировать конец строки. Вы можете продолжить строчный комментарий на следующую строку с помощью backslash-newline. Вы даже можете разделить ‘/*’, ‘*/’ и ‘//’ на несколько строк с помощью backslash-newline. Например:
/\ * */ # /* */ defi\ ne FO\ O 10\ 20
эквивалентно #define FOO 1020. Все эти приёмы очень запутанны и не должны использоваться в коде, предназначенном для чтения.
Нет способа предотвратить интерпретацию обратной косой черты в конце строки как backslash-newline. Однако это не может повлиять ни на одну корректную программу.
Далее: Токенизация, Предыдущее: Наборы символов, Вверх: Обзор [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-12.1.0/cpp/Initial-processing.html