AFAIK, этот вопрос применяется одинаково к C и C++
Шаг 6 "фаз перевода", указанных в стандарте C (5.1.1.2 в проекте C99 стандарта), указывает, что смежные строковые литералы должны быть связаны в единственный литерал. Т.е.
printf("helloworld.c" ": %d: Hello "
"world\n", 10);
Эквивалентно (синтаксически):
printf("helloworld.c: %d: Hello world\n", 10);
Однако стандарт, кажется, не указывает, который должна обработать часть компилятора, это - должно это быть препроцессором (cpp
) или сам компилятор. Некоторое исследование онлайн говорит мне, что эта функция, как обычно ожидают, будет выполнена препроцессором (источник № 1, источник № 2, и существует больше), который имеет смысл.
Однако выполнение cpp
в Linux показывает это cpp
не делает этого:
eliben@eliben-desktop:~/test$ cat cpptest.c
int a = 5;
"string 1" "string 2"
"string 3"
eliben@eliben-desktop:~/test$ cpp cpptest.c
# 1 "cpptest.c"
# 1 ""
# 1 ""
# 1 "cpptest.c"
int a = 5;
"string 1" "string 2"
"string 3"
Так, мой вопрос: где должен эта функция языка быть обработанным, в препроцессоре или самом компиляторе?
Возможно, нет никакого единственного хорошего ответа. Будут цениться эвристические ответы на основе опыта, известные компиляторы и общая хорошая техническая практика.
P.S. Если Вы задаетесь вопросом, почему я забочусь об этом... Я пытаюсь выяснить, оставляет ли мой Python, базирующийся синтаксический анализатор C должен обработать конкатенацию строкового литерала (который это не делает, в данный момент), или это cpp
который это принимает выполнения перед ним.
Стандарт не определяет препроцессор и компилятор, он просто определяет этапы трансляции, которые вы уже отметили. Традиционно фазы с 1 по 4 выполнялись в препроцессоре, фазы с 5 по 7 - в компиляторе, а фаза 8 - в компоновщике, но по стандарту это не требуется.
В стандарте ANSI C эта деталь рассматривается в разделе 5.1.1.2, пункт (6):
5.1.1.2 Фазы трансляции
...
4. Выполняются директивы предварительной обработки и расширяются вызовы макросов. ...
5. Каждый член исходного набора символов и управляющая последовательность в символьных константах и строковых литералах преобразуется в член набора символов выполнения.
6. Смежные лексемы литералов символьных строк конкатенируются, а смежные лексемы литералов широких строк конкатенируются.
Стандарт не определяет, что реализация должна использовать препроцессор и компилятор, как таковые.
Шаг 4 явно относится к обязанностям препроцессора.
Шаг 5 требует, чтобы был известен "набор символов выполнения". Эта информация также требуется компилятору. Легче переносить компилятор на новую платформу, если препроцессор не содержит зависимостей от платформы, поэтому тенденция состоит в том, чтобы реализовать шаг 5, а значит и шаг 6, в компиляторе.
Я бы обработал это в сканирующей токен части парсера, то есть в компиляторе. Это кажется более логичным. Препроцессор не обязан знать "структуру" языка, и фактически он обычно игнорирует ее, чтобы макросы могли генерировать некомпилируемый код. Он обрабатывает не более того, что ему положено обрабатывать директивами, специально адресованными ему (# ...
), а "последствия" их (как, например, от #define x h
, которое заставит препроцессор изменить множество x на h)
Если препроцессор не указан для обработки этого, можно с уверенностью предположить, что это работа компилятора.
Изменить:
Ваша ссылка « I.e. » в начале сообщения отвечает на вопрос:
Смежные строковые литералы объединяются во время компиляции; это позволяет разбивать длинные строки на несколько строк, а также позволяет добавлять строковые литералы , полученные из определений препроцессора C, и макросы к строкам во время компиляции ...
Существуют хитрые правила того, как конкатенация строковых литералов взаимодействует с escape-последовательностями. Предположим, у вас есть
const char x1[] = "a\15" "4";
const char y1[] = "a\154";
const char x2[] = "a\r4";
const char y2[] = "al";
, тогда x1
и x2
должны оказаться равными согласно strcmp
, и то же самое для y1
и ] y2
. (Это то, что Хит имеет в виду, цитируя этапы перевода - преобразование escape-последовательности происходит перед конкатенацией строковых констант.) Также существует требование, чтобы if any строковых констант в группе конкатенации имеет префикс L
или U
, вы получаете широкую строку или строку Unicode. Сложите все это вместе, и окажется, что выполнять эту работу как часть «компилятора», а не «препроцессора» значительно удобнее.