c

Expresión+(+ k--) en C



(3)

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:

#include<stdio.h> int main(){ int k = 0; while(+(+k--)!=0) k=k++; printf("%d/n", k); return 0; }

Entonces ahora podemos ver que la declaración k=k++; está dentro del bucle.

Ahora rastreemos el programa:

Cuando se evalúa por primera vez la condición del bucle, k tiene el valor 0. La expresión k-- tiene el valor actual de k , que es 0, y k se decrementa como un efecto secundario. Entonces, después de esta declaración, el valor de k es -1.

El +k-- en esta expresión no tiene efecto sobre el valor, por lo que +k-- evaluado a 0 y de forma similar +(+k--) evalúa a 0.

Entonces se evalúa el operador != . Como 0!=0 es falso, no se ingresa el cuerpo del bucle . Si se hubiera ingresado el cuerpo, invocaría un comportamiento indefinido porque k=k++ lee y escribe k sin un punto de secuencia. Pero el ciclo no se ingresa, por lo que no hay UB.

Finalmente se imprime el valor de k que es -1.

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?


Aquí hay una versión de esto que muestra la precedencia del operador:

+(+(k--))

Los dos operadores unarios + no hacen nada, por lo que esta expresión es exactamente equivalente a k-- . La persona que escribió esto probablemente estaba tratando de meterse con tu mente.


[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:

while(+(+k--)!=0)

y la declaración demente que controla:

k=k++;

Voy a cubrir la segunda parte primero.

Si tiene una variable como k que desea incrementar en 1, C le proporciona no una, ni dos, ni tres, sino cuatro formas diferentes de hacerlo:

  1. k = k + 1
  2. k += 1
  3. ++k
  4. k++

A pesar de esta recompensa (o tal vez por eso), algunos programadores se confunden y emiten contorsiones como

k = k++;

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 el valor de k = (la parte k = y la parte k++ ), 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 que no tiene un significado definido, sino 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 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 bucle corre 0 veces. Por lo tanto, este programa en particular podría no estar indefinido, pero sigue siendo patológicamente confuso.

Consulte también estas respuestas SO canónicas a todas las preguntas relacionadas con el comportamiento indefinido de este tipo.

Pero no preguntaste sobre la parte k=k++ . Usted preguntó sobre la primera parte confusa, la condición +(+k--)!=0 . 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 eso). Cualquier expresión como esta debe entenderse de adentro hacia afuera. Supongo que sabes qué

k--

hace. Toma el valor actual de k y lo "devuelve" al resto de la expresión, y disminuye más o menos simultáneamente k , es decir, almacena la cantidad k-1 nuevamente en k .

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ón

a - b

resta b de a. Y sabes que el unario menos niega las cosas: la expresión

-a

te da el negativo de a. Lo que hace unario + es ... básicamente nada. +a le da el valor de a, después de cambiar los valores positivos a valores positivos y negativos a negativos. Entonces la expresión

+k--

te da lo que k-- te dio, es decir, el antiguo valor de k .

Pero no hemos terminado, porque tenemos

+(+k--)

Esto solo toma lo que +k-- te dio, y aplica unary + a él nuevamente. Entonces te da lo que +k-- te dio, que fue lo que k-- te dio, que era el valor anterior de k .

Entonces, al final, la condición

while(+(+k--)!=0)

hace exactamente lo mismo que la condición mucho más común

while(k-- != 0)

habría hecho. (También hace lo mismo que la condición de aspecto aún más complicado, while(+(+(+(+k--)))!=0) lo hubiera hecho. Y esos paréntesis no son realmente necesarios; también lo hace lo mismo que while(+ + + +k--!=0) habría hecho)

Incluso averiguar cuál es la condición "normal"

while(k-- != 0)

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:

  1. sigue haciendo k-- , para hacer k cada vez más pequeño, pero también
  2. sigue haciendo el cuerpo del bucle, haga lo que haga.

Pero hacemos la parte k-- inmediato, antes (o en el proceso de) decidir si hacer otro viaje a través del ciclo. Y recuerde que k-- "devuelve" el antiguo valor de k , antes de disminuirlo. En este programa, el valor inicial de k es 0. Entonces k-- va a "devolver" el valor anterior 0, luego actualizar k 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 para ejecutar la declaración problemática k=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.