Linguaggio C: preincremento di intero

di il
6 risposte

Linguaggio C: preincremento di intero

Buongiorno a tutti. Sto studiando il linguaggio C, e mi sono trovato davanti a questa situazione:

int var1 = 10; int var2 = 0;

var2 = 2*(++var1 + 2) - 2*(--var1 - 2);

se eseguo il programma il valore di var2 è 10; tuttavia non ne capisco il motivo..se ho capito l'ordine di precedenza, viene eseguito prima il preincremento ed il predecremento (stesso livello di precedenza, quindi si legge da sinistra a destra), dopodiché le operazioni tra parentesi,
poi la moltiplicazione ed infine la sottrazione, per cui:

1) ++var1 // inizialmente vale 10, quindi viene incrementata di uno e diventa 11
2) --var1 // il suo nuovo valore è 11, ma viene decrementata quindi torna a 10
3) (var1 + 2) // 10 + 2 = 12
4) (var1 - 2) // 10 - 2 = 8
5) 2*(12) // 24
6) 2*(8) // 16
7) 24 - 16 // 8; quindi var2 dovrebbe essere 8?

cosa sto sbagliando? Grazie

6 Risposte

  • Re: Linguaggio C: preincremento di intero

    L'espressione viene valutata da sinistra a destra

    a) ++var1 // 11
    b) (var1 + 2) // 11 + 2 = 13
    ---
  • Re: Linguaggio C: preincremento di intero

    oregon ha scritto:


    L'espressione viene valutata da sinistra a destra

    a) ++var1 // 11
    b) (var1 + 2) // 11 + 2 = 13
    ---
    Innanzitutto grazie per la risposta

    var2 = 2*(11 + 2) - 2*(10 -2) = 2*13 - 2*8 = 26 - 16

    in effetti così il risultato è 10.

    era la soluzione a cui avevo pensato, ma ciò che mi ha mandato fuori strada è stato quest'altro esempio

    int var1 = 10; int var2 = 10;
    var2 = 2*(++var1) - 2*(--var1); //il programma restituisce zero

    se procedo da sinistra a destra

    1) ++var1 //11
    2) 2*var1 //2*11
    3) --var1 //10
    4) 2*var1 //2*10
    5) 22 - 20 //il risultato è 2
    
    #include <stdio.h>
    main()
    {
          int var1 = 10;
          int var2 = 10;
          var2 = 2*(++var1) - 2*(--var1);//non dovrebbe essere 2?
          printf("var1: %d\nvar2: %d", var1, var2); //var1 = 10; var2 = 0;
          
          printf("\n\n");
          getch();
    }
    
  • Re: Linguaggio C: preincremento di intero

    Guarda ... tornando al primo codice, due compilatori (Visual C++ e mingw di devc++) si comportano in maniera diversa.

    Il primo restituisce 8 e il secondo 10.

    Ho l'impressione che il risultato di questo tipo di espressioni sia "undefined behaviour" e quindi sono cose da gestire con attenzione ed evitare ...
  • Re: Linguaggio C: preincremento di intero

    oregon ha scritto:


    Guarda ... tornando al primo codice, due compilatori (Visual C++ e mingw di devc++) si comportano in maniera diversa.

    Il primo restituisce 8 e il secondo 10.

    Ho l'impressione che il risultato di questo tipo di espressioni sia "undefined behaviour" e quindi sono cose da gestire con attenzione ed evitare ...
    ti ringrazio, questo in qualche modo mi fa sentire meno imbranato. Sto studiando un libro, a dire il vero molto scolastico, proprio per partire dalle basi, ma ho notato che spesso si fanno degli esempi da settimana enigmistica, tipo quei due proposti. Non capisco perché lo si faccia e si preferisca far perdere ore dietro queste cose (prima di scrivervi ho cercato di comprenderne il meccanismo ed è proprio questo che mi ha portato al dubbio) quando un suggerimento come il tuo, ossia "undefined behaviour" e che potrebbe portare a risultati diversi su compilatori diversi, mi avrebbe messo l'anima in pace. Sto utilizzando devc++, suggerito dal testo, che restituisce 10 per il primo codice e zero per il secondo. Sicuramente eviterò in futuro questo tipo di istruzioni, era solo per capirne il meccanismo. Grazie ancora per la risposta e la pazienza
  • Re: Linguaggio C: preincremento di intero

    Una delle cose che imparerai con il tempo, e che chi e' "ziovine" non capisce, e' la seguente

    - benche' il linguaggio di programmazione PERMETTA la scrittura di certe espressioni
    - queste espressioni NON SI SCRIVONO/USANO perche' richiedono troppa attenzione per essere usate correttamente

    Basta poco per incorrere in qualche errore legato al diverso comportamento di qualche compilatore, errore che' per essere trovato, puo' essere un bagno di sangue e lacrime

    Il caso del pre/post incremento/decremento e' ESATTAMENTE una di queste situazioni: a te serve sapere ESATTAMENTE quello che vuoi ottenere, per cui tra:
    
    c = c+1;
    ++c;
    c++;
    
    userai quello che ti ASSICURA che il risultato e' ESATTAMENTE quello che ti serve.

    Nella fattispecie, gli autoincrementi li usi nel 99.9% dei casi solo nei cicli for, ed EVENTUALMENTE, ma anche no, quando devi scandire un vettore.

    Ad esempio, tra:
    
    c = 0;
    d = new int[10];
    
    while (c < 10) d[c++] = 0;
    
    e
    
    for (c=0; c<10; ++c) d[c] = 0;
    
    userai il secondo metodo perche' e' piu' chiaro.

    Poi ci sono i fissati dell'efficienza che PENSANO che la prima versione sia piu' efficiente della seconda, senza rendersi conto che i problemi di efficienza non sono legati a queste linee di codice, ma nella comlpessita' computazionale dell'algoritmo:

    - serve a poco migliorare le performace di qualche millisecondo (la complessita' computazionale di un ciclo, con le dovute considerazioni al contorno e', OVVIAMENTE, lineare) se l'algoritmo ha una complessita' computazionale esponenziale.


    Inoltre, il compilatore e' gia' per conto suo, in grado di fare delle ottimizzazioni che uno nemmeno si sognerebbe di fare.
    In particolare PROPRIO con i cicli, se scritti in modo canonico.
  • Re: Linguaggio C: preincremento di intero

    migliorabile ha scritto:


    Una delle cose che imparerai con il tempo, e che chi e' "ziovine" non capisce, e' la seguente

    - benche' il linguaggio di programmazione PERMETTA la scrittura di certe espressioni
    - queste espressioni NON SI SCRIVONO/USANO perche' richiedono troppa attenzione per essere usate correttamente

    Basta poco per incorrere in qualche errore legato al diverso comportamento di qualche compilatore, errore che' per essere trovato, puo' essere un bagno di sangue e lacrime

    Il caso del pre/post incremento/decremento e' ESATTAMENTE una di queste situazioni: a te serve sapere ESATTAMENTE quello che vuoi ottenere, per cui tra:
    
    c = c+1;
    ++c;
    c++;
    
    userai quello che ti ASSICURA che il risultato e' ESATTAMENTE quello che ti serve.

    Nella fattispecie, gli autoincrementi li usi nel 99.9% dei casi solo nei cicli for, ed EVENTUALMENTE, ma anche no, quando devi scandire un vettore.

    Ad esempio, tra:
    
    c = 0;
    d = new int[10];
    
    while (c < 10) d[c++] = 0;
    
    e
    
    for (c=0; c<10; ++c) d[c] = 0;
    
    userai il secondo metodo perche' e' piu' chiaro.

    Poi ci sono i fissati dell'efficienza che PENSANO che la prima versione sia piu' efficiente della seconda, senza rendersi conto che i problemi di efficienza non sono legati a queste linee di codice, ma nella comlpessita' computazionale dell'algoritmo:

    - serve a poco migliorare le performace di qualche millisecondo (la complessita' computazionale di un ciclo, con le dovute considerazioni al contorno e', OVVIAMENTE, lineare) se l'algoritmo ha una complessita' computazionale esponenziale.


    Inoltre, il compilatore e' gia' per conto suo, in grado di fare delle ottimizzazioni che uno nemmeno si sognerebbe di fare.
    In particolare PROPRIO con i cicli, se scritti in modo canonico.
    Grazie anche per la tua esaustiva risposta. In effetti dopo questa esperienza, mi terrò alla larga da espressioni di questo tipo. Tuttavia, poiché era proposta dal testo, ho cercato di capirne il meccanismo, che pensavo di aver compreso nell'espressione 2*(++var1) - 2*(--var1), ma che poi si è rivelato inesatto nell'espressione 2*(++ var1 +2 ) - 2*(--var1 -2). Grazie ancora per i chiarimenti che mi avete fornito.
Devi accedere o registrarti per scrivere nel forum
6 risposte