Spec-Zone.ru › GCC 12 CPP

1.2 Инициализация обработки

Препроцессор выполняет серию текстовых преобразований входного файла. Эти преобразования выполняются до всех остальных процессов. Концептуально они выполняются в строгом порядке, и весь файл проходит через каждое преобразование, прежде чем начнётся следующее. Компилятор CPP фактически выполняет все преобразования одновременно по причинам производительности. Эти преобразования примерно соответствуют трём «фазам трансляции», описанным в стандарте C.

  1. Вводной файл считывается в память и разбивается на строки.

    Разные системы используют разные соглашения для обозначения конца строки. GCC принимает ASCII управляющие последовательности LF, CR LF и CR в качестве маркеров конца строки. Это стандартные последовательности, используемые в Unix, DOS и VMS, а также в классической Mac OS (до OSX) соответственно. Поэтому вы можете без проблем копировать исходный код, написанный в любой из этих систем, в другую и использовать его без преобразования. (GCC может потерять отслеживание текущего номера строки, если файл не использует последовательно одну конвенцию, как это иногда происходит, когда он редактируется на компьютерах с различными конвенциями, которые используют общую файловую систему в сети.)

    Если последняя строка любого входного файла не содержит маркер конца строки, конец файла неявно считается содержащим его. Стандарт C указывает, что это условие вызывает неопределённое поведение, поэтому GCC выведет сообщение об ошибке.

  2. Если включены триграфы, они заменяются соответствующими одиночными символами. По умолчанию GCC игнорирует триграфы, но если вы запрашиваете строгое соответствие с опцией -std или опцией -trigraphs, то он преобразует их.

    Это девять трёхсимвольных последовательностей, все начинающиеся с ‘??’, которые по ISO C определены как стоящие для одиночных символов. Они позволяют устаревшим системам, которым не хватает некоторых знаков препинания языка C, использовать его. Например, ‘??/’ обозначает ‘\’, поэтому '??/n' — это символьная константа для новой строки.

    Триграфы не пользуются популярностью, и многие компиляторы реализуют их неправильно. Переносимый код не должен полагаться на преобразование или игнорирование триграфов. С опцией -Wtrigraphs GCC предупредит вас, если триграф может изменить значение вашей программы при его преобразовании. Смотрите Wtrigraphs.

    В строковой константе вы можете предотвратить, чтобы последовательность вопросительных знаков была воспринята как триграф, вставив обратную косую черту между вопросительными знаками или разделив строковый литерал на триграф и используя конкатенацию строковых литералов. "(??\?)" — это строка ‘(???)’, а не ‘(?]’. Традиционные компиляторы C не распознают эти выражения.

    Девять триграфов и их замены:

    Trigraph:       ??(  ??)  ??<  ??>  ??=  ??/  ??'  ??!  ??-
    Replacement:      [    ]    {    }    #    \    ^    |    ~
  3. Продолжающиеся строки объединяются в одну длинную строку.

    Продолжающаяся строка — это строка, которая заканчивается обратной косой чертой, ‘\’. Обратная косая черта удаляется, а следующая строка присоединяется к текущей. Пробелы не вставляются, поэтому вы можете разделить строку где угодно, даже посередине слова. (Обычно более читабельно разделять строки только в местах пробелов.)

    Конечная обратная косая черта в продолжении строки обычно называется backslash-newline.

    Если между обратной косой чертой и концом строки есть пробелы, это всё ещё продолжающаяся строка. Однако, поскольку это обычно результат ошибки редактирования, и многие компиляторы не примут это как продолжение строки, GCC выведет об этом предупреждение.

  4. Все комментарии заменяются на одиночные пробелы.

    Существует два типа комментариев. Блочные комментарии начинаются с ‘/*’ и продолжаются до следующего ‘*/’. Блочные комментарии не вложены:

    /* 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API