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

Spec-Zone.ru

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