Spec-Zone.ru › GCC 9 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, использовать C. Например, ‘??/’ означает ‘\’, поэтому '??/n' — это символьная константа для новой строки.

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

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

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

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

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

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

    Если между обратной косой чертой и концом строки есть пробелы, это всё ещё строка с продолжением. Однако, поскольку это обычно результат ошибки редактирования, и многие компиляторы не будут принимать это как строку с продолжением, 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 они являются официальной частью языка.

Поскольку эти преобразования происходят до всех других процессов, вы можете механически разделить строку с помощью обратной косой черты-новой строки в любом месте. Вы можете прокомментировать конец строки. Вы можете продолжить строчный комментарий на следующую строку с помощью обратной косой черты-новой строки. Вы даже можете разделить ‘/*’, ‘*/’, и ‘//’ на несколько строк с обратной косой чертой-новой строки. Например:

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

Spec-Zone.ru

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