literal c++ cout string-literals

c++ - literal - ¿Qué significa cout<< “/ n”[a== N]; ¿hacer?



string literal c++ (5)

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


No tengo 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 un literal de cadena . Un literal de cadena tiene el tipo de matriz de n const char , el [] es simplemente un índice en una matriz de caracteres que en este caso contiene:

/n/0

note /0 se agrega a todos los literales de cadena.

El operador == da como resultado verdadero o falso , por lo que el índice será:

  • 0 si es falso, si a no es igual a N resulta en /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 .

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

El literal de cadena tiene el tipo "matriz de n const char" , donde n es el tamaño de la cadena como se define a continuación y tiene una 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 agrega a cada literal de cadena para que los programas que escanean una cadena puedan encontrar su final.

la sección 4.5 [conv.prom] dice:

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

Escribir un carácter nulo en una secuencia de texto

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

Por lo que puedo decir, esta es una conclusión razonable, cout se define en términos de flujo C, como podemos ver en 27.4.2 [narrow.stream.objects] que dice:

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

y el borrador del estándar C11 en la sección 7.21.2 Streams dice:

[...] Los datos leídos de un flujo de texto se compararán necesariamente con los datos que se escribieron anteriormente en ese flujo solo si: los datos consisten solo en caracteres de impresión y la pestaña horizontal de caracteres de control y nueva línea;

e imprimir caracteres están cubiertos en 7.4 Manejo de caracteres <ctype.h> :

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

con nota al pie 199 dice:

En una implementación que utiliza el conjunto de caracteres ASCII de EE. UU. De siete bits, los caracteres de impresión son aquellos cuyos valores se encuentran entre 0x20 (espacio) y 0x7E (tilde); Los caracteres de control son aquellos cuyos valores se encuentran entre 0 (NUL) y 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 se indica de otra manera en esta Norma Internacional por las palabras "comportamiento indefinido" o por la omisión de cualquier definición explícita de comportamiento. [...]

También podemos ver la lógica de C99 que dice:

El conjunto de caracteres que se requiere conservar en la secuencia de texto de E / S son los necesarios para escribir programas en C; la intención es que el Estándar permita que un traductor de C se escriba de una manera máximamente portátil. Los caracteres de control como el retroceso no son necesarios para este propósito, por lo que su manejo en secuencias de texto no es obligatorio.


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

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

En la tabla de Precedencia del operador C ++ , el operator [] une más fuerte que el operator << , por lo que su código es equivalente a:

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

O, en otras palabras, el operator [] no hace nada directamente con cout . Se usa solo para indexar el literal de cadena "/n"

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

Debido a que los literales de cadena en C++ siempre terminan con un carácter nulo ( ''/0'' , L''/0'' , char16_t() , etc.), un literal de cadena "/n" es un const char[2] 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

Entonces, si a == N es verdadero (promovido a 1), la expresión "/n"[a == N] da como resultado ''/0'' y ''/n'' si el resultado es falso.

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''

typeof "/n"[a==N] es const char

Si la intención es no 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 transmisión, prefiera un código legible, por ejemplo:

cout << (a == N ? ''/0'' : ''/n'');


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 han especificado las otras respuestas, 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 un conjunto de primitivas de estilo C, array[42] es azúcar sintáctico para *(array+42) . Peor aún, no hay diferencia entre array+42 y 42+array . Esto lleva a una ofuscación interesante: use 42[array] 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 los booleanos se transforman en enteros.
    Dada una expresión de la forma a[b] , a o b debe ser una expresión de puntero y la otra; el otro debe ser una expresión entera. Dada la expresión "/n"[a==N] , el "/n" representa la parte del 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 se evalúa como false o true . Las reglas de promoción de enteros especifican que false convierte en 0 y true 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, las matrices en C y C ++ se degradan fácilmente en un puntero que apunta al primer elemento de la matriz.

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


Dado lo anterior, suponga que a==N evalúa como 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 como true , el comportamiento depende en gran medida del sistema. Según los comentarios a las respuestas a la pregunta, a Windows no le gustará eso. En sistemas tipo Unix donde std::cout se canaliza a la ventana de terminal, el comportamiento es bastante benigno. No pasa nada.


El hecho de que pueda escribir código así no significa que deba hacerlo. Nunca escribas código así.


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

El índice de matriz [a==N] evalúa como [0] o [1] e indexa la matriz de caracteres representada por "/n" que contiene una nueva línea y un carácter nulo.

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 ningún propósito en particular que no sea ofuscar; No lo considere como un ejemplo de buena práctica. Lo siguiente es preferible en la mayoría de los casos:

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

o solo:

if( a != N ) cout << `/n` ;


Probablemente sea una forma extraña de escribir.

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'' . Entonces cout<<"/n"[a==N] imprimirá un carácter ''/n'' o un carácter ''/0'' .

El problema es que no puede enviar un carácter ''/0'' a una secuencia de E / S en modo de texto. El autor de ese código podría haber notado que nada parecía suceder, por lo que asumió 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 transmisión dejará de funcionar por completo; ya no aparecerá más salida a cout .

En resumen, el efecto es,

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

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