qué hace cout <" "[a==N]; do?


En el siguiente ejemplo:

cout<<"\n"[a==N];

No tengo idea de lo que hace la opción [] en cout, pero no imprime una nueva línea cuando el valor de a es igual a N.

Author: Mohit Jain, 2015-06-17

5 answers

No tengo ni idea de lo que hace la opción [] en cout

Esto en realidad no es una opción cout, lo que está sucediendo es que "\n" es una literal de cadena. Un literal de cadena tiene el tipo array de n const char , el [] es simplemente un índice en un array de caracteres que en este caso contiene:

\n\0

Note \0 se añade a todos los literales de cadena.

El operador == da como resultado verdadero o false , así que el índice será:

  • 0 if false, if a does not equal N resulting in \n
  • 1 si es verdadero, si a es igual a N resultando en \0

Esto es bastante críptico y podría haber sido reemplazado por un simple if.

Para referencia, el estándar C++14 (La luminosidad confirmó que el borrador coincide con el estándar real ) con el borrador más cercano siendo N3936 en la sección 2.14.5 literales de cadena [lex.string] dice ( énfasis mío):

String literal tiene el tipo "array of n const char" , donde n es el tamaño de la cadena como se define a continuación, y tiene duración de almacenamiento estático (3.7).

Y:

Después de cualquier concatenación necesaria, en la fase de traducción 7 (2.2), '\0' se añade a cada cadena literal para que los programas que escanean una cadena puedan encontrar su final.

Sección 4.5 [conv.prom] dice:

Un prvalue de tipo bool se puede convertir en un prvalue de tipo int, con falso convirtiéndose en cero y verdadero convirtiéndose en uno.

Escribir un carácter nulo en un flujo de texto

Se afirmó que escribir un carácter nulo(\0) en un flujo de texto es un comportamiento indefinido.

Hasta donde puedo decir que esta es una conclusión razonable, cout se define en términos de corriente C, como podemos ver en {[19]]} [estrecho.flujo.objetos] que dice:

El objeto cout controla la salida a un búfer de flujo asociado con el objeto stdout, declarado en (27.9.2).

Y el proyecto de norma C11 en la sección 7.21.2 Corrientes dice:

[...] Los datos leídos de un flujo de texto necesariamente compararán igual a los datos que se escribieron anteriormente en ese flujo solo si: los datos consisten solo en imprimir personajes y el control de caracteres tabulación horizontal y nueva línea;

Y los caracteres de impresión están cubiertos en 7.4 Manejo de caracteres :

[...] el carácter de control del término se refiere a un miembro de un conjunto de caracteres específico de la configuración regional que no se está imprimiendo caracter.199) Todas las letras y dígitos son caracteres de impresión.

Con una nota al pie 199 que dice:

En una implementación que utiliza el ASCII US de siete bits conjunto de caracteres, los caracteres de impresión son los cuyos valores se encuentran desde 0x20 (espacio) hasta 0x7E (tilde); los caracteres de control son aquellos cuya los valores se encuentran desde 0 (NUL) hasta 0x1F (US), y el carácter 0x7F (DEL).

Y finalmente podemos ver que el resultado de enviar un carácter nulo no está especificado y podemos ver que este es un comportamiento indefinido de la sección 4 Conformidad que dice:

[...] El comportamiento indefinido es de otra manera indicado en este Estándar Internacional por las palabras "comportamiento indefinido" o por el omisión de cualquier definición explícita de comportamiento.[...]

También podemos mirar el fundamento C99 que dice:

El conjunto de caracteres que se deben conservar en E / S de flujo de texto son los necesarios para escribir C programas; la intención es que el Estándar debería permitir que un traductor de C sea escrito en un máximo moda portátil. Los caracteres de control como el retroceso no son requerido para este propósito, por lo que su el manejo en flujos de texto no es obligatorio.

 70
Author: Shafik Yaghmour,
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
2015-06-22 20:04:15
cout<<"\n"[a==N];

No tengo ni idea de lo que hace la opción [] en cout

En Tabla de precedencia del operador C++ , operator [] se une más fuerte que operator <<, por lo que su código es equivalente a:

cout << ("\n"[a==N]);  // or cout.operator <<("\n"[a==N]);

O, en otras palabras, operator [] no hace nada directamente con cout. Se utiliza solo para la indexación de cadena literal "\n"

Por ejemplo for(int i = 0; i < 3; ++i) std::cout << "abcdef"[i] << std::endl; imprimirá caracteres a, b y c en líneas consecutivas en la pantalla.


Porque literales de cadena in C++ are always terminated with null character('\0', L'\0', char16_t(), etc), una cadena literal {[10] } es un const char[2] que contiene los caracteres '\n' y '\0'

En el diseño de memoria esto se ve así:

+--------+--------+
|  '\n'  |  '\0'  |
+--------+--------+
0        1          <-- Offset
false    true       <-- Result of condition (a == n)
a != n   a == n     <-- Case

Así que si a == N es true (promovido a 1), la expresión "\n"[a == N] resulta en '\0' y '\n' si el resultado es false.

Es funcionalmente similar (no igual) a:

char anonymous[] = "\n";
int index;
if (a == N) index = 1;
else index = 0;
cout << anonymous[index];

El valor de "\n"[a==N] es '\n' o '\0'

El tipo de "\n"[a==N] es const char


Si la intención es imprimir nada (que puede ser diferente de imprimir '\0' dependiendo de la plataforma y el propósito), prefiera la siguiente línea de código:

if(a != N) cout << '\n';

Incluso si su intención es escribir '\0' o '\n' en la secuencia, prefiera un código legible, por ejemplo:

cout << (a == N ? '\0' : '\n');
 39
Author: Mohit Jain,
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
2015-06-17 19:16:19

Probablemente sea una forma extraña de escribir{[14]]}

if ( a != N ) {
    cout<<"\n";
}

El operador [] selecciona un elemento de una matriz. La cadena "\n" es en realidad una matriz de dos caracteres: una nueva línea '\n' y un terminador de cadena '\0'. Así que cout<<"\n"[a==N] imprimirá un carácter '\n' o un carácter '\0'.

El problema es que no se le permite enviar un carácter '\0' a una secuencia de E/S en modo texto. El autor de ese código podría haber notado que nada parecía suceder, por lo que asumimos que cout<<'\0' es una forma segura de no hacer nada.

En C y C++, esa es una suposición muy pobre debido a la noción de comportamiento indefinido. Si el programa hace algo que no está cubierto por la especificación del estándar o la plataforma en particular, cualquier cosa puede suceder. Un resultado bastante probable en este caso es que la secuencia dejará de funcionar por completo - no aparecerá más salida a cout en absoluto.

En resumen, el efecto es,

"Imprimir una nueva línea si a no es igual a N. De lo contrario, no lo sé. Choque o algo así."

{y la moraleja es, no escribas las cosas tan crípticamente.

 9
Author: Potatoswatter,
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
2015-06-17 10:35:05

No es una opción de cout sino un índice de matriz de "\n"

El array index [a==N] se evalúa como [0] o [1], e indexa el array de caracteres representado por "\n" que contiene una nueva línea y un carácter nul.

Sin embargo, pasar nul al iostream tendrá resultados indefinidos, y sería mejor pasar una cadena:

cout << &("\n"[a==N]) ;

Sin embargo, el código en cualquier caso no es particularmente aconsejable y no sirve para otro propósito particular que ofuscar; no lo considere como un ejemplo de buenas prácticas. Lo siguiente es preferible en la mayoría de los casos:

cout << (a != N ? "\n" : "") ;

O simplemente:

if( a != N ) cout << `\n` ;
 8
Author: Clifford,
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
2015-06-20 07:49:56

Cada una de las siguientes líneas generará exactamente la misma salida:

cout << "\n"[a==N];     // Never do this.
cout << (a==N)["\n"];   // Or this.
cout << *((a==N)+"\n"); // Or this.
cout << *("\n"+(a==N)); // Or this.


Como las otras respuestas han especificado, esto no tiene nada que ver con std::cout. En cambio es una consecuencia de

  • Cómo se implementa el operador de suscripción primitivo (no sobrecargado) en C y C++.
    En ambos lenguajes, si array es una matriz de primitivas estilo C, array[42] es azúcar sintáctica para *(array+42). Peor aún, no hay diferencia entre array+42 y 42+array. Esto conduce a ofuscación interesante: Use 42[array] en lugar de array[42] si su objetivo es ofuscar completamente su código. No hace falta decir que escribir 42[array] es una idea terrible si su objetivo es escribir código comprensible y mantenible.

  • Cómo se transforman los booleanos en enteros.
    Dada una expresión de la forma a[b], a o b debe ser una expresión puntero y la otra; la otra debe ser una expresión entera. Dada la expresión "\n"[a==N], el "\n" representa el parte puntero de esa expresión y el a==N representa la parte entera de la expresión. Aquí, a==N es una expresión booleana que evalúa a false o true. Las reglas de promoción de enteros especifican que false se convierte en 0 y true se convierte en 1 en la promoción a un entero.

  • Cómo los literales de cadena se degradan en punteros.
    Cuando se necesita un puntero, los arrays en C y C++ se degradan fácilmente en un puntero que apunta al primer elemento del matriz.

  • Cómo se implementan los literales de cadena.
    Cada literal de cadena de estilo C se añade con el carácter nulo '\0'. Esto significa que la representación interna de su "\n" es el array {'\n', '\0'}.


Dado lo anterior, supongamos que a==N evalúa a false. En este caso, el comportamiento está bien definido en todos los sistemas: obtendrá una nueva línea. Si, por otro lado, a==N evalúa a true, el comportamiento es altamente dependiente del sistema. Basado en comentarios a las respuestas a la pregunta, a Windows no le gustará eso. En sistemas tipo Unix donde std::cout es canalizado a la ventana terminal, el comportamiento es bastante benigno. No pasa nada.


Solo porque puedas escribir código así no significa que debas hacerlo. Nunca escribas código así.

 8
Author: David Hammen,
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
2015-06-24 02:31:29