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, sia
no es igual aN
resulta en/n
-
1
si es verdadero, sia
es igual aN
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, siarray
es un conjunto de primitivas de estilo C,array[42]
es azúcar sintáctico para*(array+42)
. Peor aún, no hay diferencia entrearray+42
y42+array
. Esto lleva a una ofuscación interesante: use42[array]
lugar dearray[42]
si su objetivo es ofuscar completamente su código. No hace falta decir que escribir42[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 formaa[b]
,a
ob
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 ela==N
representa la parte entera de la expresión. Aquí,a==N
es una expresión booleana que se evalúa comofalse
otrue
. Las reglas de promoción de enteros especifican quefalse
convierte en 0 ytrue
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 aN
De lo contrario, no lo sé. Accidente o algo así".
... y la moraleja es, no escribas cosas tan crípticamente.