Vi esta pregunta en una prueba en la que tenemos que decirle a la salida del siguiente código.
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
La salida es -1
. Sin embargo, no estoy seguro de por qué esta es la respuesta.
¿Qué significa la expresión +(+k--)
en C?
k=k++
no está definido, pero no está indefinido porque nunca se ejecutó debido a una condición ofuscada, estoy votando para cerrar como un duplicado de esta pregunta .Respuestas:
[Para el registro, he editado esta respuesta bastante significativamente desde que fue aceptada y votada. Sin embargo, todavía dice básicamente las mismas cosas.]
Este código es profundamente, quizás deliberadamente, confuso. Contiene una instancia estrechamente evitada del comportamiento temible indefinido . Es básicamente imposible determinar si la persona que formuló esta pregunta era muy, muy inteligente o muy, muy estúpida. Y la "lección" que este código puede pretender enseñar o cuestionar sobre usted, es decir, que el operador unario plus no hace mucho, ciertamente no es lo suficientemente importante como para merecer este tipo de dirección subversiva.
Hay dos aspectos confusos del código, la extraña condición:
y la declaración demente que controla:
Voy a cubrir la segunda parte primero.
Si tiene una variable como
k
esa que desea incrementar en 1, C le proporciona no una, ni dos, ni tres, sino cuatro formas diferentes de hacerlo:k = k + 1
k += 1
++k
k++
A pesar de esta recompensa (o quizás por eso), algunos programadores se confunden y emiten contorsiones como
Si no puede averiguar qué se supone que debe hacer, no se preocupe: nadie puede hacerlo. Esta expresión contiene dos intentos diferentes de alterar
k
el valor (lak =
parte y lak++
parte), y debido a que no hay una regla en C para decir cuál de las modificaciones intentadas "gana", una expresión como esta está formalmente indefinida , lo que significa no solo eso no tiene un significado definido, pero que todo el programa que lo contiene es sospechoso.Ahora, si observa con mucho cuidado, verá que en este programa en particular, la línea en
k = k++
realidad no se ejecuta, porque (como estamos a punto de ver) la condición de control es inicialmente falsa, por lo que el ciclo se ejecuta 0 veces . Por lo que este programa en particular no podría en realidad ser indefinido - pero sigue siendo confuso patológicamente.Consulte también estas respuestas SO canónicas a todas las preguntas relacionadas con el comportamiento indefinido de este tipo.
Pero no preguntaste sobre el
k=k++
papel. Preguntaste sobre la primera parte confusa, la+(+k--)!=0
condición. Esto se ve extraño, porque es extraño. Nadie jamás jamás escribiría dicho código en un programa real. Entonces no hay razón para aprender cómo entenderlo. (Sí, es cierto, explorar los límites de un sistema puede ayudarlo a aprender sobre sus puntos finos, pero en mi libro hay una línea bastante clara entre exploraciones imaginativas y sugerentes versus exploraciones malintencionadas y abusivas, y esta expresión es muy clara en el lado equivocado de esa línea.)De todos modos, examinemos
+(+k--)!=0
. (Y después de hacerlo, olvidémonos de todo). Cualquier expresión como esta debe entenderse de adentro hacia afuera. Supongo que sabes quéhace. Toma
k
el valor actual y lo "devuelve" al resto de la expresión, y disminuye más o menos simultáneamentek
, es decir, almacena la cantidadk-1
nuevamentek
.Pero entonces, ¿qué hace el
+
? Esto es unario más, no binario más. Es como el unario menos. Sabes que el binario menos hace resta: la expresiónresta b de a. Y sabes que el unario menos niega las cosas: la expresión
te da el negativo de a. Lo que
+
hace unario es ... básicamente nada.+a
le daa
el valor, después de cambiar los valores positivos a valores positivos y negativos a negativos. Entonces la expresiónte da lo que sea que te haya
k--
dado, es decir,k
el viejo valor.Pero no hemos terminado, porque tenemos
Esto solo toma lo que
+k--
te dio, y se aplica+
de nuevo a él. Entonces te da lo que te+k--
dio, que fue lo quek--
te dio, que erak
el valor anterior.Entonces, al final, la condición
hace exactamente lo mismo que la condición mucho más común
habría hecho. (También hace lo mismo que la condición de aspecto aún más complicado
while(+(+(+(+k--)))!=0)
hubiera hecho. Y esos paréntesis no son realmente necesarios; también hace lo mismo quewhile(+ + + +k--!=0)
hubiera hecho).Incluso averiguar cuál es la condición "normal"
hace es un poco complicado. Hay dos cosas que suceden en este ciclo: a medida que el ciclo se ejecuta potencialmente varias veces, vamos a:
k--
, para hacerk
cada vez más pequeño, pero tambiénPero hacemos la
k--
parte de inmediato, antes (o en el proceso de) decidir si hacer otro viaje a través del ciclo. Y recuerde quek--
"devuelve" el valor anterior dek
, antes de disminuirlo. En este programa, el valor inicial dek
es 0. Pork--
lo tanto, va a "devolver" el valor anterior 0, luego actualizark
a -1. Pero el resto de la condición es!= 0
, pero como acabamos de ver, la primera vez que probamos la condición, obtuvimos un 0. Así que no haremos ningún viaje a través del ciclo, por lo que no intentaremos ejecutar el declaración problemáticak=k++
en absoluto.En otras palabras, en este ciclo particular, aunque dije que "están ocurriendo dos cosas", resulta que la cosa 1 sucede una vez, pero la cosa 2 ocurre cero veces.
En cualquier caso, espero que ahora esté suficientemente claro por qué esta pobre excusa para un programa termina imprimiendo -1 como el valor final de
k
. Normalmente, no me gusta responder preguntas de preguntas como esta, se siente como hacer trampa, pero en este caso, dado que estoy tan en desacuerdo con todo el punto del ejercicio, no me importa.fuente
A primera vista, parece que este código invoca un comportamiento indefinido, sin embargo, ese no es el caso.
Primero formateemos el código correctamente:
Así que ahora podemos ver que la declaración
k=k++;
está dentro del ciclo.Ahora rastreemos el programa:
Cuando la condición del bucle se evalúa por primera vez,
k
tiene el valor 0. La expresiónk--
tiene el valor actual dek
, que es 0, yk
se disminuye como un efecto secundario. Entonces, después de esta declaración, el valor dek
es -1.El inicio
+
de esta expresión no tiene ningún efecto sobre el valor, por lo que se+k--
evalúa a 0 y se+(+k--)
evalúa de manera similar a 0.Luego
!=
se evalúa al operador. Como0!=0
es falso, no se ingresa el cuerpo del bucle . Si se hubiera ingresado el cuerpo, invocaría un comportamiento indefinido porquek=k++
tanto las lecturas como las escriturask
sin un punto de secuencia. Pero el ciclo no se ingresa, por lo que no hay UB.Finalmente
k
se imprime el valor de que es -1.fuente
if (x != NULL) *x = 42;
¿Esto es indefinido cuandox == NULL
? Por supuesto no. El comportamiento indefinido no ocurre en partes del código que no se ejecutan. La palabra comportamiento es una pista. El código que no se ejecuta no tiene comportamiento, indefinido o no.k=k++
es cualitativamente diferente de*x=42
. El último está bien definido six
es un puntero válido, pero el primero no está definido, pase lo que pase. (Admito que puede que tengas razón, pero de nuevo, no voy a discutir sobre eso, y me preocupa cada vez más que hayamos sido controlados magistralmente)Aquí hay una versión de esto que muestra la precedencia del operador:
Los dos
+
operadores unarios no hacen nada, por lo que esta expresión es exactamente equivalente ak--
. La persona que escribió esto probablemente estaba tratando de meterse con tu mente.fuente