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

Spec-Zone.ru

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