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: [ ] { } # \ ^ | ~ - Строки, продолженные на следующей строке, объединяются в одну длинную строку.
Строка, продолженная на следующей строке, — это строка, заканчивающаяся обратной косой чертой ‘\’. Обратная косая черта удаляется, а следующая строка присоединяется к текущей. Пробелы не вставляются, поэтому вы можете разделить строку в любом месте, даже посреди слова. (Обычно лучше делить строки только на пробелах.)
Обратная косая черта в конце продолженной строки обычно называется обратная косая черта-новая строка.
Если между обратной косой чертой и концом строки есть пробелы, это всё ещё продолженная строка. Однако, поскольку это обычно результат ошибки редактирования, и многие компиляторы не примут это как продолженную строку, 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-11.4.0/cpp/Initial-processing.html