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

Spec-Zone.ru

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