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

Spec-Zone.ru

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