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

Spec-Zone.ru

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