Если у меня есть многострочная строковая константа С++ 11, такая как
R"""line 1
line 2
line3"""
Определено ли, из каких символов состоит терминатор/разделитель строки?
Если у меня есть многострочная строковая константа С++ 11, такая как
R"""line 1
line 2
line3"""
Определено ли, из каких символов состоит терминатор/разделитель строки?
Цель состоит в том, чтобы новая строка в необработанном строковом литерале сопоставлялась с одним символом '\n'
. Это намерение выражено не так ясно, как следовало бы, что привело к некоторой путанице.
Цитаты относятся к стандарту ISO C++ 2011 года.
Во-первых, вот доказательство того, что оно соответствует одному символу '\n'
.
В примечании к параграфу 4 раздела 2.14.5 [lex.string] говорится:
[ Примечание. Новая строка исходного файла в необработанном строковом литерале приводит к новой строке в результирующем выполнении string-literal. Предполагая отсутствие пробелов в начале строк в следующем примере, утверждение завершится успешно:
const char *p = R"(a\
b
c)";
assert(std::strcmp(p, "a\\\nb\nc") == 0);
— конец примечания ]
Здесь четко указано, что новая строка отображается на один символ '\n'
. Это также соответствует наблюдаемому поведению g++ 6.2.0 и clang++ 3.8.1 (тесты, выполненные в системе Linux с использованием исходных файлов с окончаниями строк в стиле Unix и Windows).
Учитывая четко сформулированное намерение в примечании и поведение двух популярных компиляторов, я бы сказал, что на это можно положиться, хотя было бы интересно посмотреть, как на самом деле справляются с этим другие компиляторы.
Однако буквальное прочтение нормативной формулировки стандарта может легко привести к другому выводу или, по крайней мере, к некоторой неопределенности.
В параграфе 3 раздела 2.5 [lex.pptoken] говорится (выделено мной):
Между начальными и конечными символами двойных кавычек необработанной строки любые преобразования, выполненные на этапах 1 и 2 (триграфы, универсальные имена символов и объединение строк) отменяются. ; эта реверсия должна применяться до того, как будет идентифицирована любая d-char, r-char или разделительная скобка.
Фазы перевода указаны в 2.2 [lex.phases]. На этапе 1:
Символы физического исходного файла сопоставляются способом, определяемым реализацией, с базовым исходным набором символов (с введением символов новой строки для индикаторов конца строки), если это необходимо.
Если мы предположим, что сопоставление символов физического исходного файла с базовым набором символов и введение символов новой строки являются «преобразованиями», мы могли бы разумно заключить, что, например, новая строка в середине необработанного строкового литерала в исходном файле формата Windows должен быть эквивалентен последовательности \r\n
. (Я могу представить, что это полезно для кода, специфичного для Windows.)
(Эта интерпретация действительно приводит к проблемам с системами, в которых индикатор конца строки не является последовательностью символов, например, где каждая строка представляет собой запись фиксированной ширины. Такие системы в наши дни редкость.)
Как указывает ответ "Cheers and hth. - Alf", существует открытый Отчет о дефекте для этой проблемы. Оно было подано в 2013 году и до сих пор не решено.
Лично я думаю, что корень путаницы в слове «любой» (курсив добавлен, как и раньше):
Между начальными и конечными символами двойных кавычек необработанной строки любые преобразования, выполненные на этапах 1 и 2 (триграфы, универсальные имена символов и объединение строк) отменяются. ; эта реверсия должна применяться до того, как будет идентифицирована любая d-char, r-char или разделительная скобка.
Конечно, сопоставление физических символов исходного файла с базовым набором исходных символов можно разумно рассматривать как преобразование. Предложение в скобках «(триграфы, универсальные имена символов и соединение строк)», по-видимому, предназначено для указания какие преобразования должны быть отменены, но это либо попытка изменить значение слова « преобразования» (которые стандарт формально не определяет) или противоречит использованию слова «любой».
Я полагаю, что замена слова «любой» на «определенный» намного яснее отразила бы очевидное намерение:
Между начальными и конечными символами двойных кавычек необработанной строки некоторые преобразования, выполненные на этапах 1 и 2 (триграфы, универсальные имена символов и объединение строк), отменяются; эта реверсия должна применяться до того, как будет идентифицирована любая d-char, r-char или разделительная скобка.
Эта формулировка делает более ясным, что «триграфы, универсальные имена символов и сращивание строк» являются единственными преобразованиями, которые должны быть отменены. (Не все, что делается на этапах перевода 1 и 2, отменяется, только те определенные перечисленные преобразования.)
\n
. Потому что иначе не будет работать на этих системах.
- person Cheers and hth. - Alf; 06.10.2016
\n
, но эквивалентен управляющей последовательности \n
.
- person Keith Thompson; 30.03.2020
\n
, как вы написали выше? Я уверен, вы знаете, что [lex.string]/3 это просто примечание.
- person Belloc; 30.03.2020
\n
. Спасибо за ваши комментарии.
- person Belloc; 31.03.2020
\n
в символьном литерале представляет собой символ новой строки. Он ничего не говорит о необработанных строковых литералах.
- person Keith Thompson; 31.03.2020
Стандарт, кажется, указывает, что:
R"""line 1
line 2
line3"""
эквивалентно:
"line 1\nline 2\nline3"
Из 2.14.5 строковых литералов стандарта C++11:
4 [ Примечание. Новая строка исходного файла в необработанном строковом литерале приводит к новой строке в результирующем выполнении строкового литерала. Предполагая отсутствие пробелов в начале строк в следующем примере, утверждение завершится успешно:
const char *p = R"(a\ b c)"; assert(std::strcmp(p, "a\\\nb\nc") == 0);
—конец примечания ]
5 [ Пример: Необработанная строка
R"a( )\ a" )a"
эквивалентно
"\n)\\\na\"\n"
.
\r
.
- person user207421; 06.10.2016
Примечание: после публикации ответов вопрос существенно изменился. Остается только половина, а именно аспект чистого C++. Сетевой фокус в этом ответе касается исходного вопроса об отправке многострочной строки на сервер с четко определенными требованиями к концу строки. Я не гонюсь за эволюцией вопросов вообще.
Внутри программы стандартом C++ для новой строки является \n
. Это также используется для новой строки в необработанном литерале. Для необработанных литералов нет специального соглашения.
Обычно \n
соответствует переводу строки ASCII, значение которого равно 10.
Я не уверен, что это соответствует EBCDIC, но вы можете проверить это, если необходимо.
Однако в сети, у меня сложилось впечатление, что большинство протоколов используют возврат каретки ASCII плюс перевод строки, то есть 13, за которым следует 10. Это иногда называют CRLF, после аббревиатур ASCII CR для возврата каретки и LF для перевода строки. . Когда escape-последовательности С++ отображаются в ASCII, это просто \r\n
в С++.
Вы должны соблюдать требования протокола, который вы используете.
Для обычного файлового/потокового ввода-вывода стандартная библиотека C++ заботится о сопоставлении внутреннего \n
с любым соглашением, которое использует хост-среда. Это называется текстовым режимом, в отличие от бинарного режима, в котором сопоставление не выполняется.
Для сетевого ввода-вывода, который не поддерживается стандартной библиотекой, код приложения должен делать это сам, либо напрямую, либо через некоторые библиотечные функции.
По этому поводу существует активная проблема, Отчет о дефектах основного языка № 1655 Окончания строк в необработанных строковых литералах, представленный Майком Миллером 26 апреля 2013 г., где он спрашивает:
предполагается, что, например, CRLF в исходном строковом литерале должен быть представлен как символ новой строки или как исходные символы?
Поскольку значения окончания строки различаются в зависимости от кодировки исходного файла и учитывая, что в некоторых файловых системах не используется кодировка окончания строки, а вместо этого строки представляют собой записи, ясно, что намерение не представить содержимое файла как есть, поскольку это невозможно сделать во всех случаях. Но насколько я вижу, этот DR еще не решен.
\n
. Я не понимаю, как ты не смог это прочитать.
- person Cheers and hth. - Alf; 06.10.2016
\n
сопоставляется с переводом строки. Если в стандарте есть что-то, что отвечает на этот вопрос, или что «сопоставляет новую строку с \n
», что не обязательно одно и то же, вы должны процитировать и процитировать это.
- person user207421; 06.10.2016
R""" """
(должна быть новая строка между """
, но, конечно, она не будет отображаться в комментариях) и "\n"
эквивалентны, вы должны сказать это явно (и желательно привести доказательства).
- person Tavian Barnes; 06.10.2016
'\n'
соответствует переводу строки. Он даже не упоминает символ перевода строки. В нем говорится, что '\n'
отображается на новую строку.
- person Keith Thompson; 06.10.2016
\r\n
для HTTP, почты и т. д. - person user207421   schedule 06.10.2016R"(""line 1
? - person wally   schedule 06.10.2016\n
, который представляет0x0A
в самом программном коде (точно так же, как новые строки в других строковых константах), но разные среды будут переводить его в свои собственные новые строки (например, CRLF в Windows). - person Justin Time - Reinstate Monica   schedule 06.10.2016