Прерывания ключевых слов C

#c

#c

Вопрос:

Давайте рассмотрим два примера наличия «материала» между ключевым словом:

 #include <stdio.h>

int main(void)
{
    printf("OKn");
    pri
ntf("OKn");             // version 1
    pri/**/ntf("Hi");    // version 2
    return 0;
}
 

То есть наличие комментария /* ... */ и /n . Как предполагается обрабатывать эти два, или это зависит от компилятора?

Комментарии:

1. Это недопустимо.

2. @suriyel правильно, да, он не компилируется. Мне просто интересно, каковы правила замены комментариев и новых строк в препроцессоре перед компиляцией.

Ответ №1:

Я сохраняю код в файле a.cpp , затем предварительно скомпилируйте код:

 gcc -E a.cpp
 

Вывод:

 int main(void)
{
    printf("OKn");
    printf("OKn");

    pri ntf("Hi");
    return 0;
}
 

В первом случае компиляция может пройти. но во втором случае gcc заменит /**/ на пустой, после чего компиляция завершится неудачно.

gcc и clang имеют одинаковый результат в этом случае. Это стандарт C.

Комментарии:

1. комплайнер работает в 3 этапа: предварительная компиляция, компиляция, связывание. -E предварительно компилируется

2. @David542 это означает только предварительную обработку, но не компиляцию gcc.godbolt.org/z/Evde36

Ответ №2:

Из этапов перевода C99:

Приоритет среди синтаксических правил перевода определяется следующими этапами.

  1. Многобайтовые символы физического исходного файла сопоставляются, определенным реализацией образом, с исходным набором символов (при необходимости вводятся символы новой строки для индикаторов конца строки). Последовательности триграфов заменяются соответствующими односимвольными внутренними представлениями.
  2. Каждый экземпляр символа обратной косой черты (), за которым сразу следует символ новой строки, удаляется, соединяя физические исходные строки для формирования логических исходных строк. Только последняя обратная косая черта в любой строке физического источника должна иметь право быть частью такого соединения. Исходный файл, который не является пустым, должен заканчиваться символом новой строки, которому не должен непосредственно предшествовать символ обратной косой черты, прежде чем произойдет любое такое объединение.
  3. Исходный файл разбивается на токены предварительной обработки и последовательности символов пробела (включая комментарии). Исходный файл не должен заканчиваться частичным маркером предварительной обработки или частичным комментарием. Каждый комментарий заменяется одним пробелом. Символы новой строки сохраняются. Сохраняется ли каждая непустая последовательность символов пробела, отличных от символа новой строки, или заменяется одним символом пробела, определяется реализацией.
  4. […]
     pri
ntf("OKn");             // version 1
 

Допустимо, поскольку оно анализируется как printf("OKn"); после шага 2 выше.

     pri/**/ntf("Hi");    // version 2
 

Недопустимый, так как он анализируется, как pri ntf("Hi"); после шага 3 выше.

Комментарии:

1. Интересно, почему я никогда не понимал, каким образом обратная косая черта в конце строки должна была немедленно сопровождаться новой строкой без завершающих пробелов, когда некоторые форматы текстовых файлов не различают строки, которые имеют или не имеют завершающих пробелов. Если бы был разрешен пробел после завершающей обратной косой черты, тогда не было бы необходимости беспокоиться о том, импортируются ли записи фиксированной длины с заполнением пробелов или без них, поскольку завершающие пробелы не будут иметь значения в любом другом контексте.

2. @supercat Предполагаю, что должна быть какая-то историческая причина, как и в случае с другими причудами C, но я так и не понял, в чем конкретно могла заключаться эта причина. Это было реальной проблемой в далеком прошлом, когда некоторые редакторы, которых лучше оставить неназванными, иногда добавляли пробелы в конце строк во время так называемой навигации в виртуальном пространстве.

3. @supercat Обратная косая черта экранирует следующий символ. Если это новая строка, это означает, что мы, люди, хотим видеть разрыв строки, но компилятор не должен. Если это не новая строка, следующий символ экранируется с другим значением. — Ваш вопрос должен быть скорее » Почему мой текстовый инструмент (он же редактор) не различает эти случаи? Почему он не показывает мне пробелы? » И вы измените свои предпочтения… — Если в последовательностях символов есть значение, инструменты для их создания должны им подчиняться. Если вы хотите иметь фиксированную длину, вставьте необходимые пробелы перед обратной косой чертой / последним символом.

4. @thebusybee: Некоторые системы хранят текстовые файлы в виде записей фиксированной длины с заполнением пробелов. Перфокарты не могли вместить набор символов C (включая такие важные функции, как строчные буквы), но системы на основе EBCDIC, которые были созданы на основе систем, используемых с перфокартами, могли. В таких системах нет символа «новой строки», но он выводится в конце каждой записи. Что касается обратной косой черты, «экранирующей следующий символ», она обычно используется для экранирования последовательности. Так же, как x и попытка экранировать последующие символы из набора [0-9A-Fa-f], , не было бы…

5. …концептуальная проблема с приглашением реализаций интерпретировать обратную косую черту, за которой следует пробел, не являющийся символом новой строки, как экранирующий все до следующей новой строки (кричащий, если он встречает что-либо, кроме пробелов). Одной из причин приоритетного использования сращивания новой строки было обеспечение возможности автоматического преобразования исходного файла, содержащего длинные исходные строки, для использования в системе, которая использует, например, фиксированные 72- или 80-символьные записи, поэтому в ней есть необычные правила, которые отличаются от правил обратной косой черты в других контекстах.