Реализация конкатенации строкового литерала в C и C++

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 который это принимает выполнения перед ним.

7
задан Brian Tompsett - 汤莱恩 25 February 2016 в 22:52
поделиться

5 ответов

Стандарт не определяет препроцессор и компилятор, он просто определяет этапы трансляции, которые вы уже отметили. Традиционно фазы с 1 по 4 выполнялись в препроцессоре, фазы с 5 по 7 - в компиляторе, а фаза 8 - в компоновщике, но по стандарту это не требуется.

8
ответ дан 6 December 2019 в 15:18
поделиться

В стандарте ANSI C эта деталь рассматривается в разделе 5.1.1.2, пункт (6):

5.1.1.2 Фазы трансляции
...

4. Выполняются директивы предварительной обработки и расширяются вызовы макросов. ...

5. Каждый член исходного набора символов и управляющая последовательность в символьных константах и строковых литералах преобразуется в член набора символов выполнения.

6. Смежные лексемы литералов символьных строк конкатенируются, а смежные лексемы литералов широких строк конкатенируются.

Стандарт не определяет, что реализация должна использовать препроцессор и компилятор, как таковые.

Шаг 4 явно относится к обязанностям препроцессора.

Шаг 5 требует, чтобы был известен "набор символов выполнения". Эта информация также требуется компилятору. Легче переносить компилятор на новую платформу, если препроцессор не содержит зависимостей от платформы, поэтому тенденция состоит в том, чтобы реализовать шаг 5, а значит и шаг 6, в компиляторе.

2
ответ дан 6 December 2019 в 15:18
поделиться

Я бы обработал это в сканирующей токен части парсера, то есть в компиляторе. Это кажется более логичным. Препроцессор не обязан знать "структуру" языка, и фактически он обычно игнорирует ее, чтобы макросы могли генерировать некомпилируемый код. Он обрабатывает не более того, что ему положено обрабатывать директивами, специально адресованными ему (# ... ), а "последствия" их (как, например, от #define x h, которое заставит препроцессор изменить множество x на h)

0
ответ дан 6 December 2019 в 15:18
поделиться

Если препроцессор не указан для обработки этого, можно с уверенностью предположить, что это работа компилятора.

Изменить:

Ваша ссылка « I.e. » в начале сообщения отвечает на вопрос:

Смежные строковые литералы объединяются во время компиляции; это позволяет разбивать длинные строки на несколько строк, а также позволяет добавлять строковые литералы , полученные из определений препроцессора C, и макросы к строкам во время компиляции ...

3
ответ дан 6 December 2019 в 15:18
поделиться

Существуют хитрые правила того, как конкатенация строковых литералов взаимодействует с 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. Сложите все это вместе, и окажется, что выполнять эту работу как часть «компилятора», а не «препроцессора» значительно удобнее.

1
ответ дан 6 December 2019 в 15:18
поделиться