c# - org - ¿Cuándo++ no produce los mismos resultados que+1?
mapwindows 5 (15)
Los siguientes dos fragmentos de código C # producen resultados diferentes (suponiendo que el nivel de la variable se usa tanto antes como después de la llamada recursiva). ¿Por qué?
public DoStuff(int level)
{
// ...
DoStuff(level++);
// ...
}
,
public DoStuff(int level)
{
// ...
DoStuff(level+1);
// ...
}
Después de leer algunas de las respuestas a continuación, pensé que valdría la pena publicar los rastreos de pila para el nivel ++, ++ y el nivel + 1 para resaltar lo engañoso que es este problema.
Los he simplificado para esta publicación. La secuencia de llamada recursiva comienza con DoStuff (1).
// nivel ++
DoStuff(int level = 1)
DoStuff(int level = 2)
DoStuff(int level = 2)
DoStuff(int level = 2)
// nivel ++
DoStuff(int level = 4)
DoStuff(int level = 4)
DoStuff(int level = 3)
DoStuff(int level = 2)
// nivel + 1
DoStuff(int level = 4)
DoStuff(int level = 3)
DoStuff(int level = 2)
DoStuff(int level = 1)
Cuando utiliza un lenguaje que permite la sobrecarga del operador, y ''+ <integer>'' se ha definido para hacer algo diferente a post- y prefijo ''++''.
Por otra parte, solo he visto tales abominaciones en proyectos escolares *, si te topas con eso en la naturaleza probablemente tengas una razón realmente buena, bien documentada.
[* una pila de enteros, si no me equivoco. ''++'' y ''-'' pulsado y reventado, mientras ''+'' y ''-'' realizan aritmética normal]
El primer ejemplo usa el valor de ''índice'', incrementa el valor y actualiza el ''índice''.
El segundo ejemplo usa el valor de ''índice'' más 1, pero no cambia el contenido de ''índice''.
Por lo tanto, dependiendo de lo que quiera hacer aquí, ¡podría haber algunas sorpresas en la tienda!
El primer fragmento de código utiliza el operador de incremento posterior a la operación, por lo que la llamada se realiza como DoStuff (nivel) ;. Si desea utilizar un operador de incremento aquí, use DoStuff (++ level) ;.
El primero es usar el valor en nivel y ENTONCES incrmentarlo.
El último está usando el nivel + 1 como una variable pasada.
En el nivel ++ estás usando el operador postfix. Este operador funciona después de que se usa la variable. Es decir, después de que se coloca en la pila para la función llamada, se incrementa. Por otro lado, el nivel + 1 es una expresión matemática simple y se evalúa y el resultado se pasa a la función llamada. Si desea incrementar la variable primero y luego pasarla a la función llamada, puede usar el operador de prefijo: nivel ++
En lo que respecta a mi experiencia, la expresión del parámetro se evalúa primero y obtiene un valor de nivel. La variable en sí misma se incrementa antes de que se llame a la función, porque al compilador no le importa si está usando la expresión como parámetro o de lo contrario ... Todo lo que sabe es que debe incrementar el valor y obtener el valor anterior como resultado del expresión.
Sin embargo, en mi opinión, código como este es realmente descuidado, ya que al tratar de ser inteligente, hace que tenga que pensar dos veces acerca de lo que realmente está sucediendo.
Mientras que es tentador reescribir como:
DoStuff(++level);
Personalmente, creo que esto es menos legible que incrementar la variable antes de la llamada al método. Como se señala en un par de las respuestas anteriores, lo siguiente sería más claro:
level++;
DoStuff(level);
Para aclarar todas las otras respuestas:
+++++++++++++++++++++
DoStuff(a++);
Es equivalente a:
DoStuff(a);
a = a + 1;
+++++++++++++++++++++
DoStuff(++a);
Es equivalente a:
a = a + 1;
DoStuff(a);
+++++++++++++++++++++
DoStuff(a + 1);
Es equivalente a:
b = a + 1;
DoStuff(b);
+++++++++++++++++++++
Porque el primer ejemplo es realmente equivalente a:
public DoStuff(int level)
{
// ...
int temp = level;
level = level + 1;
DoStuff(temp);
// ...
}
Tenga en cuenta que también puede escribir ++ level; eso sería equivalente a:
public DoStuff(int level)
{
// ...
level = level + 1;
DoStuff(level);
// ...
}
Lo mejor es no abusar de los operadores ++ y - en mi opinión; rápidamente se vuelve confuso y / o indefinido lo que realmente está sucediendo, y los compiladores modernos de C ++ no generan códigos más eficientes con estos operadores de todos modos.
level + 1 envía cualquier nivel + 1 a la función. level ++ envía nivel a la función y luego la incrementa.
Podrías hacer ++ niveles y eso probablemente te daría los resultados que deseas.
level++
devuelve el valor actual del level
, luego aumenta el level
. level+1
no cambia el level
en absoluto, pero se llama a DoStuff
con el valor de (level + 1)
.
level ++ pasará el nivel a DoStuff y luego incrementará el nivel para usarlo en el resto de la función. Esto podría ser un error bastante desagradable ya que la recursión nunca terminará (de lo que se muestra a DoStuff siempre se le está pasando el mismo valor). Quizás ++ significa en cambio, porque es lo opuesto al nivel ++ (incrementa el nivel y pasa el valor incrementado a DoStuff ).
level + 1 pasará el nivel + 1 a DoStuff y dejará el nivel sin cambios para el resto de la función.
public DoStuff(int level)
{
// DoStuff(level);
DoStuff(level++);
// level = level + 1;
// here, level''s value is 1 greater than when it came in
}
En realidad, aumenta el valor del nivel.
public DoStuff(int level)
{
// int iTmp = level + 1;
// DoStuff(iTmp);
DoStuff(level+1);
// here, level''s value hasn''t changed
}
en realidad no incrementa el valor del nivel.
No es un gran problema antes de la llamada a la función, pero después de la llamada a la función, los valores serán diferentes.
el valor de retorno del level++
será el level
y, therefore
pasará el level
a DoStuff
. Esto podría ser un error bastante desagradable ya que la recursión nunca terminará (de lo que se muestra DoStuff
siempre se pasa con el mismo valor). ¿Quizás se quiere decir ++level
o level + 1
su lugar?
level + 1
pasará el level + 1
a DoStuff
y dejará el level
sin cambios para el resto de la función.
El operador de incremento posterior (variable ++) es precisamente equivalente a la función
int post_increment(ref int value)
{
int temp = value;
value = value + 1
return temp;
}
mientras que el operador de preincremento (variable ++) es precisamente equivalente a la función
int pre_increment(ref int value)
{
value = value + 1;
return value;
}
Por lo tanto, si expande el operador en línea en el código, los operadores son equivalentes a:
DoStuff(a + 1)
int temp = a + 1;
DoStuff(temp);
DoStuff(++a)
a = a + 1;
DoStuff(a);
DoStuff(a++);
int temp = a;
a = a + 1;
DoStuff(temp);
Es importante tener en cuenta que el incremento posterior no es equivalente a:
DoStuff(a);
a = a + 1;
Además, como punto de estilo, no se debe incrementar un valor a menos que la intención sea usar el valor incrementado (una versión específica de la regla, "no asigne un valor a una variable a menos que planee usar ese valor"). ) Si el valor i + 1
nunca se usa nuevamente, entonces el uso preferido debería ser DoStuff(i + 1)
y no DoStuff(++i)
.
Para decirlo de la manera más simple, ++var
es un operador de prefijo e incrementará las variables antes de que se evalúe el resto de la expresión. var++
, un operador de postfijo, incrementa una variable después de que se evalúa el resto de la expresión. Y como otros lo han mencionado, por supuesto, var+1
crea solo una variable temporal (separada en la memoria) que se inicia con var
y se incrementa con la constante 1
.