Spec-Zone.ru › GCC 8 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-8.5.0/cpp/Initial-processing.html

Spec-Zone.ru

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