Почему объявления строковых литералов C/С++ должны быть однострочными?
Есть ли какая-то особая причина, что многострочные строковые литералы, такие как следующие, не разрешены в С++?
string script =
"
Some
Formatted
String Literal
";
Я знаю, что многострочные строковые литералы могут быть созданы путем размещения обратной косой черты перед каждой новой строкой.
Я пишу язык программирования (похожий на C) и хотел бы облегчить создание многострочных строк (как в приведенном выше примере).
Есть ли какая-либо техническая причина для исключения такого рода строкового литерала? В противном случае мне пришлось бы использовать строковый литерал типа python с тройной цитатой (чего я не хочу делать):
string script =
"""
Some
Formatted
String Literal
""";
Почему объявления строковых литералов C/С++ являются однострочными?
Ответы
Ответ 1
Следует учитывать, что C был написан не как язык программирования "Приложения", а как язык системного программирования. Не было бы неправильно сказать, что он был разработан специально для переписывания Unix. Имея это в виду, не было EMACS или VIM, и ваши пользовательские интерфейсы были последовательными терминалами. Многострочные строковые объявления кажутся немного бессмысленными в системе, в которой нет многострочного текстового редактора. Кроме того, манипуляции со строками не будут основной проблемой для тех, кто хочет написать ОС в данный конкретный момент времени. Традиционный набор инструментов сценариев UNIX, таких как AWK и SED (среди многих других), является свидетельством того факта, что они не использовали C для выполнения значительных манипуляций со строками.
Дополнительные соображения: в начале 70-х годов (когда был написан C) было весьма распространено подавать свои программы на PUNCH CARDS и возвращаться на следующий день, чтобы получить их. Не потратил ли бы это дополнительное время на компиляцию программы с многострочными строковыми литералами? На самом деле, нет. На самом деле это может быть меньше работы для компилятора. Но ты все равно собирался вернуться на следующий день в большинстве случаев. Но никто, кто заполнял перфокарту, не собирался помещать большие объемы текста, которые не были нужны в их программах.
В современной среде, вероятно, нет причин не включать многострочные строковые литералы, кроме предпочтений дизайнера. Грамматически говоря, это, вероятно, проще, потому что вам не нужно принимать во внимание перевод строки при анализе строкового литерала.
Ответ 2
Тесный ответ "потому что грамматика запрещает многострочные строковые литералы". Я не знаю, есть ли веские причины для этого, кроме исторических причин.
Есть, конечно, способы обойти это. Вы можете использовать сращивание строк:
const char* script = "\
Some\n\
Formatted\n\
String Literal\n\
";
Если символ \
отображается как последний символ в строке, новая строка будет удалена во время предварительной обработки.
Или вы можете использовать конкатенацию строковых литералов:
const char* script =
" Some\n"
" Formatted\n"
" String Literal\n";
Смежные строковые литералы объединяются во время предварительной обработки, поэтому в момент компиляции они заканчиваются как один строковый литерал.
Используя любой метод, строковый литерал заканчивается так, как если бы он был написан:
const char* script = " Some\n Formatted\n String Literal\n";
Ответ 3
Другие упоминали некоторые отличные обходные пути, я просто хотел решить причину.
Причина в том, что C был создан в то время, когда обработка была в прейскуранте, а компиляторы должны были быть простыми и как можно быстрее. В эти дни, если бы C обновлялся (я смотрю на вас, C1X), вполне возможно сделать именно то, что вы хотеть. Однако это маловероятно. В основном по историческим причинам; такое изменение может потребовать обширных перезаписи компиляторов, и поэтому, вероятно, будет отклонено.
Ответ 4
В дополнение к существующим ответам вы можете обойти это, используя строковые литералы С++ 11, например:
#include <iostream>
#include <string>
int main() {
std::string str = R"(a
b)";
std::cout << str;
}
/* Output:
a
b
*/
[n3290: 2.14.5/4]:
[Примечание: новая строка исходного файла в исходной строке литеральный результат в новой строке в результате выполнения Строка литерала. Предполагая, что пробелы в начале строк в в следующем примере утверждение будет успешным:
const char *p = R"(a\
b
c)";
assert(std::strcmp(p, "a\\\nb\nc") == 0);
-end note]
Несмотря на ненормативную, эта заметка и пример, который следует за ней в [n3290: 2.14.5/5]
, служат дополнением к показанию в грамматике, что в произведении r-char-sequence
могут содержаться символы новой строки (тогда как производство s-char-sequence
, используемое для нормальных строковых литералов, не может).
Ответ 5
Препроцессор C работает поэтапно, но с лексическими токенами. Это означает, что препроцессор понимает, что "foo"
является токеном. Однако, если C допускает многострочные литералы, препроцессор будет в беде. Рассмотрим:
"foo
#ifdef BAR
bar
#endif
baz"
Препроцессор не может взаимодействовать с внутренней частью токена, но он работает поочередно. Итак, как он должен справиться с этим делом? Простое решение - просто полностью запретить многострочные строки.
Ответ 6
Собственно, вы можете разбить его так:
string script =
"\n"
" Some\n"
" Formatted\n"
" String Literal\n";
Смежные строковые литералы объединяются компилятором.
Ответ 7
Строки могут располагаться на нескольких строках, но каждая строка должна указываться отдельно:
string script =
" \n"
" Some \n"
" Formatted \n"
" String Literal ";
Ответ 8
Я пишу язык программирования (похоже на C) и хотел бы позволить легко писать многострочные строки (например, в приведенном выше примере).
Нет причин, по которым вы не могли бы создать язык программирования, который допускает многострочные строки.
Например, Vedit Macro Language (который является языком сценариев C для текстового редактора VEDIT) допускает многострочные строки, например:
Reg_Set(1,"
Some
Formatted
String Literal
")
Это зависит от вас, как вы определяете свой синтаксис языка.
Ответ 9
Вы также можете сделать:
string useMultiple = "this"
"is "
"a string in C.";
Поместите один литерал за другим без особых символов.
Ответ 10
Литературные объявления не должны быть однострочными.
GPUImage вставляет многострочный код шейдера. Оформить свой макрос SHADER_STRING.