C++: ¿Hay una definición estándar para fin de línea en una constante de cadena de varias líneas?


Si tengo una cadena multi-línea C++11 cadena constante como

R"""line 1
line 2
line3"""

¿Está definido en qué carácter consiste el terminador/separador de líneas?

Author: Mark Harrison, 2016-10-06

3 answers

La intención es que una nueva línea en un literal de cadena sin procesar se asigne a una sola '\n' carácter. Esta intención no se expresa tan claramente como debería ser, lo que ha llevado a cierta confusión.

Las citas corresponden al estándar ISO C++ de 2011.

Primero, aquí está la evidencia de que se asigna a un único carácter '\n'.

Una nota en la sección 2.14.5 [lex.string] el párrafo 4 dice:

[ Nota: Una nueva línea de archivo fuente en un literal de cadena sin procesar resulta en un nueva línea en la ejecución resultante string-literal. Suponiendo que no espacio en blanco al principio de las líneas en el siguiente ejemplo, el assert tendrá éxito:

    const char *p = R"(a\
    b
    c)";
    assert(std::strcmp(p, "a\\\nb\nc") == 0);

- nota final ]

Esto indica claramente que una nueva línea se asigna a un único '\n' caracter. También coincide con el comportamiento observado de g++ 6.2.0 y clang++ 3.8.1 (pruebas realizadas en un sistema Linux utilizando archivos fuente con Finales de línea estilo Unix y estilo Windows).

Dado el intención claramente declarada en la nota y el comportamiento de dos compiladores populares, yo diría que es seguro confiar en esto though aunque sería interesante ver cómo otros compiladores realmente manejan esto.

Sin embargo, una lectura literal de la normativa redacción de la estándar podría llevar fácilmente a una conclusión diferente, o al menos a cierta incertidumbre.

Sección 2.5 [lex.pptoken] el párrafo 3 dice (énfasis añadido):

Entre la comilla doble inicial y final personajes de la string raw, cualquier transformación realizada en las fases 1 y 2 (trigraphs, universal-character-names, and line splicing) se revierten; esta reversión se aplicará antes de cualquier d-char, r-char, o paréntesis delimitador se identifica.

Las fases de la traducción se especifican en 2.2 [lex.fase]. En la fase 1:

Los caracteres del archivo de origen físico se mapean, en un manera definida para la implementación, para el conjunto de caracteres de origen básico (introducción de caracteres de nueva línea para los indicadores de final de línea) si necesario.

Si asumimos que la asignación de caracteres de archivo de origen físico a la el conjunto básico de caracteres y la introducción de caracteres de nueva línea son " tranformations ", podríamos concluir razonablemente que, por ejemplo, una nueva línea en el medio de un literal de cadena sin procesar en un formato de Windows el archivo fuente debe ser equivalente a una secuencia \r\n. (Puedo imaginar ese ser útil para código específico de Windows.)

(Esta interpretación da lugar a problemas con los sistemas donde la el indicador de fin de línea no es una secuencia de caracteres, por ejemplo donde cada línea es un registro de ancho fijo. Tales sistemas son raros estos días.)

Como "Salud y hth. - Respuesta de Alf señala, hay un abierto Informe de defectos para este número. It was submitted in 2013 and has not yet been resuelto.

Personalmente, creo que la raíz de la confusión es la palabra " cualquier" (sin cursivas en el original):

Entre las comillas dobles iniciales y finales del raw string, cualquier transformaciones realizadas en las fases 1 y 2 (trigraphs, universal-character-names, and line splicing) are reverted; this la reversión se aplicará antes de cualquier d-char, r-char, o delimitar se identifican paréntesis.

Seguramente la asignación de caracteres de archivo de origen físico a el se puede pensar razonablemente en un conjunto de caracteres de origen básico como una transformación . La cláusula entre paréntesis "(trigraphs, universal-character-names, and line splicing)" seems to be intended para especificar qué transformaciones deben revertirse, pero que cualquiera de los dos intentos de cambiar el significado de la palabra "transformaciones" (que la norma no define formalmente) o contradice el uso de la palabra "cualquiera".

Sugiero que cambiar la palabra "cualquiera" a "cierto" sería Express la intención aparente mucho más claramente:

Entre las comillas dobles iniciales y finales del raw string, ciertas transformaciones realizadas en las fases 1 y 2 (trigraphs, universal-character-names, and line splicing) are reverted; this la reversión se aplicará antes de cualquier d-char, r-char, o delimitar se identifican paréntesis.

Esta redacción haría mucho más claro que " trigraphs, nombres de caracteres universales, y línea de empalme " son los únicos transformaciones que van a ser revertidas. (No todo hecho en las fases de traducción 1 y 2 se revierte, sólo los específicos transformaciones listadas.)

 27
Author: Keith Thompson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:33:29

El estándar parece indicar que:

R"""line 1
line 2
line3"""

Es equivalente a:

"line 1\nline 2\nline3"

De 2.14.5 Literales de cadena del estándar C++11:

4 [ Nota: Una nueva línea del archivo fuente en un literal de cadena sin procesar resulta en una nueva línea en la ejecución resultante literal de cadena. Suponiendo que no haya espacios en blanco al principio de las líneas en el siguiente ejemplo, la afirmación tendrá éxito:

const char *p = R"(a\
b
c)";
assert(std::strcmp(p, "a\\\nb\nc") == 0);

-nota final ]

5 [ Ejemplo: La cadena sin procesar

R"a(
)\
a"
)a"

Es equivalente a "\n)\\\na\"\n".

 15
Author: R Sahu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-06 00:11:02

Nota: la pregunta ha cambiado sustancialmente desde que se publicaron las respuestas. Solo queda la mitad, es decir, el aspecto puro de C++. El enfoque de red en esta respuesta aborda la pregunta original "enviar una cadena multilínea a un servidor con requisitos de fin de línea bien definidos". No persigo la cuestión de la evolución en general.

Internamente en el programa, el estándar de C++ para nueva línea es \n. Esto se usa también para nueva línea en un literal raw. No hay especial convención para literales crudos.

Normalmente \n se asigna a la línea ASCII, que es el valor 10.

No estoy seguro de a qué se asigna en EBCDIC, pero puede comprobarlo si es necesario.

En el cable, sin embargo, tengo la impresión de que la mayoría de los protocolos usan retorno de carro ASCII más alimentación de línea, es decir, 13 seguido de 10. Esto a veces se llama CRLF , después de las abreviaturas ASCII CR para retorno de carro y LF para alimentación de línea. Cuando los escapes de C++ se asignan a ASCII esto es simplemente \r\n en C++.

Debe cumplir con los requisitos del protocolo que está utilizando.

Para e/s de archivo/flujo ordinario, la biblioteca estándar de C++ se encarga de mapear el \n interno a cualquier convención que use el entorno host. Esto se llama modo de texto, a diferencia de modo binario donde no se realiza ninguna asignación.

Para e / s de red, que no está cubierta por la biblioteca estándar, el código de la aplicación debe hacerlo por sí mismo, ya sea directamente o a través de algunas funciones de biblioteca.


Hay un problema activo sobre esto, informe de defectos del lenguaje central #1655 "Finales de línea en literales de cadena sin procesar", enviado por Mike Miller 2013-04-26, donde pregunta,

" ¿se pretende que, por ejemplo, un CRLF en la fuente de un literal de cadena sin procesar se represente como un carácter de nueva línea o como los caracteres originales?

Dado que los valores finales de línea difieren dependiendo de la codificación de la archivo original, y teniendo en cuenta que en algunos sistemas de archivos no es una codificación de terminaciones de línea, sino líneas como registros, está claro que la intención no es representar el contenido del archivo tal cual, ya que eso es imposible de hacer en todos los casos. Pero por lo que puedo ver este DR aún no está resuelto.

 9
Author: Cheers and hth. - Alf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-07 05:05:34