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' — это символьная константа для новой строки.Триграфы не популярны, и многие компиляторы реализуют их неправильно. Переносимый код не должен полагаться на преобразование или игнорирование триграфов. С
-WtrigraphsGCC предупредит вас, когда триграф может изменить смысл вашей программы, если он будет преобразован. См. 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-4.9.4/cpp/Initial-processing.html