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, использовать C. Например, ‘??/’ означает ‘\’, поэтому '??/n' — это символьная константа для новой строки.
Триграфы не популярны, и многие компиляторы реализуют их неправильно. Переносимый код не должен полагаться на преобразование или игнорирование триграфов. С -Wtrigraphs GCC предупредит вас, когда триграф может изменить смысл вашей программы, если он будет преобразован. См. Wtrigraphs.
В строковой константе вы можете предотвратить отождествление последовательности вопросительных знаков с триграфом, вставив обратную косую черту между вопросительными знаками или разделив строковую литерал на триграф и используя конкатенацию строковых литералов. "(??\?)" — это строка ‘(???)’, а не ‘(?]’. Традиционные C-компиляторы не распознают эти конструкции.
Девять триграфов и их замены:
Trigraph: ??( ??) ??< ??> ??= ??/ ??' ??! ??- Replacement: [ ] { } # \ ^ | ~ - Строки с продолжением объединяются в одну длинную строку.
Строка с продолжением — это строка, заканчивающаяся обратной косой чертой, ‘\’. Обратная косая черта удаляется, а следующая строка присоединяется к текущей. Пробелы не вставляются, поэтому вы можете разделить строку в любом месте, даже посреди слова. (Обычно более удобочитаемо разделять строки только на пробелы.)
Конечная обратная косая черта в строке с продолжением обычно называется обратная косая черта-новая строка.
Если между обратной косой чертой и концом строки есть пробелы, это всё ещё строка с продолжением. Однако, поскольку это обычно результат ошибки редактирования, и многие компиляторы не будут принимать это как строку с продолжением, 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 они являются официальной частью языка.
Поскольку эти преобразования происходят до всех других процессов, вы можете механически разделить строку с помощью обратной косой черты-новой строки в любом месте. Вы можете прокомментировать конец строки. Вы можете продолжить строчный комментарий на следующую строку с помощью обратной косой черты-новой строки. Вы даже можете разделить ‘/*’, ‘*/’, и ‘//’ на несколько строк с обратной косой чертой-новой строки. Например:
/\ * */ # /* */ defi\ ne FO\ O 10\ 20
эквивалентно #define FOO 1020. Все эти уловки чрезвычайно запутывают и не должны использоваться в коде, предназначенном для удобочитаемости.
Нет способа предотвратить интерпретацию обратной косой черты в конце строки как обратной косой черты-новой строки. Это не может повлиять на любую корректную программу, однако.
Далее: Токенизация, Предыдущее: Наборы символов, Вверх: Обзор [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-9.5.0/cpp/Initial-processing.html