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

Spec-Zone.ru

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