2009-11-05 20 views
5

posibles duplicados:
What is more efficient i++ or ++i?
How do we explain the result of the expression (++x)+(++x)+(++x)?
Difference between i++ and ++i in a loop?diferencia entre ++ i y i ++

Hola Estoy tratando estos dos programas

void fun(){ 
    int k=0; 
    int i=10; 
    k = (i++)+(++i); 
    cout<<k<<endl; 

} 
Output = 22 as i++ will give 10 and ++i will evaluate into 12 

pero

void fun(){ 
    int k=0; 
    int i=10; 
    k = (++i)+(++i); 
    cout<<k<<endl; 

} 
Output = 24 

Debe ser 23 supongo que o hay algo que no soy capaz de ver

Gracias de antemano

+5

No, el resultado para ambos no está definido (o está definido por la implementación) porque el estándar no garantiza el orden en que se evalúan los elementos en una expresión. –

+0

mi profesor dijo que debería evitarse i ++, i + = 1 es más seguro en C++ – derrdji

+2

@derrdji - Su profesor es un poco demasiado cauteloso, y también ignora las situaciones donde la precedencia y/o las reglas de evaluación de 'i ++' y '++ i' son bastante útiles. El hecho de que algo pueda ser abusado no significa que no deba aprender cómo usarlo correctamente. –

Respuesta

19

Nota: está invocando un comportamiento indefinido (modificación de una variable de dos veces entre los puntos de secuencia)

+1

Brian's es la respuesta correcta. Este es el párrafo 2 de la norma ANSI C sección 6.3 "Expresiones" - "Entre el punto de secuencia anterior y siguiente, un objeto tendrá su valor almacenado modificado a lo sumo una vez por la evaluación de una expresión. Además, solo se tendrá acceso al valor anterior. para determinar el valor que se almacenará ". –

+9

Es un poco aterrador ver cuántas personas respondieron la pregunta * sin * captar la parte no definida. Lamentablemente, la mayoría de las personas consideran que lo que funciona con sus compiladores y casos de prueba es "válido" ... – DevSolar

+0

Creo que la razón por la que las personas respondieron (incluyéndome a mí) es que la pregunta es "¿Qué está pasando?". Creo que muchas personas simplemente tratan de explicar por qué basándose en los comportamientos que son visibles. Personalmente nunca utilizo el operador '++' excepto en for loop. – NawaMan

0

Supongo que ambos operadores de preincremento se están ejecutando antes de que se calcule la declaración de adición. por lo tanto, 24.

Todo depende de cómo ve el compilador lo que está haciendo, pero supongo que eso es lo que está viendo.

+0

Todo depende de cómo el compilador ordene sub expresiones. –

-2

++ sucede antes de calcular la expresión completa e i ++ sucede después. En el primer ejemplo ocurre uno de los incrementos antes de calcular el valor, entonces "i" se convierte en 21 y obtienes 21 + 21. En el último ejemplo ambos suceden antes, entonces "i" se convierte en 22 y obtienes 22 + 22.

0

i ++ es post-incremento, ++ i es pre-incremento. i ++ aumentará i después de que se complete la declaración.

Para ilustrar en sus ejemplos:

Ejemplo 1:

k = 0 
i = 10 

i += 1 
k = i + i // 11 + 11 
i += 1 

Ejemplo 2:

k = 0 
i = 10 

i += 1 
i += 1 
k = i + i // 12 + 12 
+0

Hombre! Tu explicación es mucho más concisa. :-D – NawaMan

+1

También es igualmente incorrecto. El código de OP invoca un comportamiento indefinido, que este código no hace porque 'i' nunca se asigna a más de una vez en ninguna instrucción. Por lo tanto, el código del OP puede hacer cualquier cosa que los escritores del compilador quieran, pero este código estará bien definido para todos los compiladores. Es inútil tratar de explicar el comportamiento indefinido, y mucho mejor reescribirlo para que sea un comportamiento definido. –

+1

Esto realmente no responde la pregunta de por qué el compilador lo ve de esta manera en lugar de asignar el resultado a dos temporales y luego agregar ambos. –

-1

++ daré resultado i = i + 1. Si i = 10, entonces en k = (++ i) + (++ i); expresión (++ i) dará un valor incrementado, lo que significa que se producirá el primer incremento, pero en el caso de i ++, el incremento se verá afectado en i después de la expresión.

Así i = 10

k = (i ++) + (++ i);

10 11 12 

10 + 12=22 

k = (++ i) + (++ i);

11 11 12 

    11 + 12=23 
+0

Pero él quiere saber por qué obtiene 24, donde solo tienes 23 haciéndolo a mano. –

+1

Los resultados dependen de cómo el compilador reordena las subexpresiones dentro del código de salida. Por lo tanto, en realidad existen múltiples soluciones válidas diferentes (válidas para el punto de vista de un ingeniero compilador, no desde el punto de vista del idioma). –

-1

++i generalmente devuelve una referencia a la propia variable de modo que la segunda modificación también afecta a la memoria que contiene el resultado de la primera modificación. (Incremento posterior i++, por otro lado, tiene que devolver una copia del valor para que funcione correctamente.)

Una definición típica de ++i en C++ (utilizando la sobrecarga de operadores) sería

struct Foo{ 
    //... 
    Foo const & operator++(){ //this implements ++i 
    //do something to increment 
    return *this; 
    } 
    Foo operator++(int){ //this implements i++ 
    Foo old(*this); 
    //do something to increment 
    return old; 
    } 
}; 
+0

@kbloom, normalmente implementaría el operador de incremento adicional en términos del operador de preincremento. Por lo tanto, su comentario "// hacer algo para incrementar" en su operador posterior al incremento simplemente invocaría al operador de preincremento. Consulte el artículo de Herb Sutter sobre el gurú de la semana para obtener más información: http://www.gotw.ca/gotw/004.htm – Void

+0

Eso es cierto. Mi punto, sin embargo, era explicar por qué ambos operadores de preincremento parecen devolver números pares (o por qué ambos parecen devolver números impares) cuando parece que uno debe devolver un número par y uno debe devolver un número impar. La respuesta a eso es que el preincremento devuelve la ubicación de la memoria real del valor que se incrementó, no una copia. –

4

Esto pareció muy interesante, por lo que tomó un vistazo en el desmontaje (MSVC++ 2008)

 k = (++i)+(++i); 
0122413C mov   eax,dword ptr [i] 
0122413F add   eax,1 
01224142 mov   dword ptr [i],eax 
01224145 mov   ecx,dword ptr [i] 
01224148 add   ecx,1 
0122414B mov   dword ptr [i],ecx 
0122414E mov   edx,dword ptr [i] 
01224151 add   edx,dword ptr [i] 
01224154 mov   dword ptr [k],edx 

Como puede ver, incrementa i dos veces y luego agrega i a sí mismo. Lo mismo sucede si hay varias instancias de (++i).

De todos modos, dado que el estándar no garantiza nada, la modificación de i más de una vez conducirá a un comportamiento indefinido.

-2

Para determinar esto, se está llevando a cabo el siguiente paso.

1). Se determina todo ++i.

2). El valor de i se usa luego para cada término que es ++i y i++.

3). Se determina todo i++.

Primer caso:

 int k=0; 
    int i=10; 
    k = (i++)+(++i);

1) Hay uno de ++i así que al entonces final de este paso i = 11 (una vez).

2) Ahora que se convierta en k = (11)+(11);

3) Hay uno de i++ así que al entonces final de este paso i = 12 (una vez).

Segundo caso:

 int k=0; 
    int i=10; 
    k = (++i)+(++i);

1) Hay uno de ++i así que al entonces final de este paso i = 12 (dos veces).

2) Ahora que se convierta en k = (12)+(12);

3) Hay uno de i++ así que al entonces final de este paso i = 12 (tiempo cero).

creo un código de prueba:

#include <stdio.h> 
int main(void) { 
    int K=0; 
    int I=10; 
    K = (I++)+(++I); 
    printf("I: %d; K: %d\n", I, K); 

    K=0; 
    I=10; 
    K = (++I)+(++I); 
    printf("I: %d; K: %d\n", I, K); 
}

Cuando se ejecuta, el resultado es:

I: 12; K: 22 
I: 12; K: 24

Espero que esto ayude.

+0

Por lo tanto, en su ejemplo, el PRIMER caso debe imprimir un número impar (eso es lo que obtuvo cuando lo hizo a mano), pero imprimió un número par cuando lo ejecutó. Él quiere saber qué pasa con eso. –

+0

¿Cómo puede ser un número impar, (11) + (11) es 22 no es un número impar. Por favor, lea el número 2) cuidadosamente, el valor de '++ i' se usa para' ++ i' y 'i ++' porque i de 'i ++' se incrementará más tarde (por lo tanto, antes de aumentarlo, es 11 ya que fue aumentado por '++ i'). Es por eso que K es (11) + (11). – NawaMan

+0

No hay una explicación determinista para el comportamiento del programa porque el comportamiento no está definido. En la práctica, el resultado diferirá de un compilador a otro, para diferentes configuraciones de traducción en el mismo compilador, e incluso para diferentes contextos en el mismo programa. La "explicación" que proporcionó es completamente inútil, ya que el comportamiento real es esencialmente aleatorio. – AnT

6

Según C++ 03 estándar 5/4 el comportamiento de los programas en cuestión no está definida:

Excepto donde se indique, el orden de evaluación de los operandos de los operadores y subexpresiones de indicación vidual individuales expresiones, y el orden en que se producen los efectos secundarios, no se especifica. 53) Entre el anterior y el siguiente punto de secuencia, un objeto escalar tendrá su valor almacenado modificado a lo sumo por la evaluación de una expresión. Además, se accederá al valor anterior solo para determinar el valor que se almacenará. Los requisitos de este párrafo se cumplirán para cada ordenamiento permitido de las subexpresiones de una expresión completa ; de lo contrario, el comportamiento no está definido.

2

Una variable nunca se debe aumentar más de una vez dentro de una sentencia, porque el comportamiento del compilador no está definido.

Para evitar los efectos secundarios, haga dos afirmaciones para sus ejemplos.

Ejemplo 1: k = i ++; k + = ++ i;

Ejemplo 2: k = ++ i; k + = ++ i;

Si lo hace, su código funcionará correctamente.

Cuestiones relacionadas