Valore in Output differente da quello aspettato

di il
21 risposte

Valore in Output differente da quello aspettato

Buongiorno a tutti, oggi mi sono imbattuto su di un programma che mi torna un risultato diverso da quello aspettato ma non riesco a capire il perchè... potreste aiutarmi per favore?
int x = -1, y = 3, z = -5;

int f( int p ) {

    return 2 * ( x *= p ) - y;

}

int main( void ) {

    z = 5 * x - f( y += 6 );

    return 0; 
}

Secondo il mio calcolo dovrebbe tornare z= 5*-9 - (-27) = -18
Ma se vado a fare una printf della Z mi risulta 22

21 Risposte

  • Re: Valore in Output differente da quello aspettato

    Veramente la printf della z dà -18
  • Re: Valore in Output differente da quello aspettato

    oregon ha scritto:


    Veramente la printf della z dà -18
    Io l'ho compilato sia su Clion che su gdb è la printf della Z torna della 22 [url=https://ibb.co/51BNyV]
  • Re: Valore in Output differente da quello aspettato

    E' un tipico caso di come i compilatori fanno il parsing dell'espressione e si comportano con la x :
    se si valuta per quello che è da sinistra a destra come fa gcc il risultato è 22
    se si valuta per quello che è da destra a sinistra come fa VC il risultato è -18
    Un po' come quelle espressioni tipo 22 / 11 * 2 che ogni tanto si trovano in giro per la rete.
  • Re: Valore in Output differente da quello aspettato

    shodan ha scritto:


    E' un tipico caso di come i compilatori fanno il parsing dell'espressione e si comportano con la x :
    se si valuta per quello che è da sinistra a destra come fa gcc il risultato è 22
    se si valuta per quello che è da destra a sinistra come fa VC il risultato è -18
    Un po' come quelle espressioni tipo 22 / 11 * 2 che ogni tanto si trovano in giro per la rete.
    Quindi si ricade in un Unspecified behaviour, ho capito bene? Oppure in un Undefined?
  • Re: Valore in Output differente da quello aspettato

    Direi la prima, anche se il termine più adatto sarebbe ill formed in quanto non è specificato (non ricordo se lo standard lo fa, ma in apparenza no) l'ordine di valutazione delle variabili globali.
  • Re: Valore in Output differente da quello aspettato

    Nel caso di operatori con eguale priorità (caso dell'espressione con / e * ), che io sappia, la valutazione è da sinistra a destra.

    Ma se compare una chiamata a funzione, se non ricordo male, dovrebbe essere valutata prima la funzione e poi il resto. Se la funzione modifica la variabile globale, ovviamente il risultato ne risente. Quindi mi sentirei di ritenere il comportamento del Visual C più adeguato.

    https://it.cppreference.com/w/cpp/language/operator_precedence
  • Re: Valore in Output differente da quello aspettato

    oregon ha scritto:


    Nel caso di operatori con eguale priorità (caso dell'espressione con / e * ), che io sappia, la valutazione è da sinistra a destra.

    Ma se compare una chiamata a funzione, se non ricordo male, dovrebbe essere valutata prima la funzione e poi il resto. Se la funzione modifica la variabile globale, ovviamente il risultato ne risente. Quindi mi sentirei di ritenere il comportamento del Visual C più adeguato.

    https://it.cppreference.com/w/cpp/language/operator_precedence
    Lo standard C da quello che ricordo non dichiara esplicitamente quale debba essere l'espressione valutata per prima perché cosi facendo ogni implementazione può scegliere la più efficace. Però io sono un novellino quindi non so dirvi
  • Re: Valore in Output differente da quello aspettato

    La tabella che ho indicato è riferita al C++, questa quella del C

    https://en.cppreference.com/w/c/language/operator_precedence

    e in effetti lo standard non indica una regola precisa.

    Come è indicato

    "The standard itself doesn't specify precedence levels. They are derived from the grammar."

    Quel codice non andrebbe scritto in quel modo (è un cattivo esempio di programmazione), anche se dal punto di vista didattico è indicativo.
    Andrebbe almeno spezzato in due righe
    
    w = f( y += 6 );
    z = 5 * x - w;
    
    oppure
    
    w = 5 * x;
    z = w - f( y += 6 );;
    
    a seconda se vuoi che la x della moltiplicazione sia intesa con il valore precedente o seguente la modifica fatta dalla funzione.
  • Re: Valore in Output differente da quello aspettato

    Grazie mille gentilissimi, abbiamo risolto l'arcano
  • Re: Valore in Output differente da quello aspettato

    Secondo CppReference
    For non-boolean operands, the expression ++x is exactly equivalent to x += 1, and the expression --x is exactly equivalent to x -= 1
    Quindi a rigor di logica dovrebbe essere un pre incremento, o no?
  • Re: Valore in Output differente da quello aspettato

    Castellina95 ha scritto:


    Grazie mille gentilissimi, abbiamo risolto l'arcano
    Non credo, o almeno io non ho capito!
    Non mi pare che siano stati determinati in modo chiaro quelli che sono i confini dell'indeterminazione (il gioco di parole in questo caso è voluto).

    oregon ha scritto:


    La tabella che ho indicato è riferita al C++, questa quella del C

    https://en.cppreference.com/w/c/language/operator_precedence

    e in effetti lo standard non indica una regola precisa.

    Come è indicato

    "The standard itself doesn't specify precedence levels. They are derived from the grammar."

    ...
    Le mie conoscenze non mi permettono di apprezzare appieno quell'inciso, ma mi sembra che nel tentativo di fornire una spiegazione tu stia ipotizzando una differenza tra C e C++ che credo in realtà non esista, infatti anche il link in italiano relativo al C++ dice la stessa cosa:
    La stessa norma non specifica i livelli di precedenza. Esse derivano dalla grammatica.

    shodan ha scritto:


    ...
    Un po' come quelle espressioni tipo 22 / 11 * 2 che ogni tanto si trovano in giro per la rete.
    Scusami, probabilmente non ho capito bene il parallelismo, ma quell'espressione è univoca (22/11*2=4).

    Secondo me per inquadrare meglio la questione (ipotizzando di trascurare per il momento il concetto di valutazione a corto-circuito) bisogna ragionare sul fatto che precedenza e associatività degli operatori sono concetti ben distinti dall'ordine di valutazione degli operandi. Senza dimenticare anche l'indeterminazione introdotta in alcuni casi dai side-effect.
    In ogni caso per giungere ad una risposta definitiva devo ragionarci ancora!
  • Re: Valore in Output differente da quello aspettato

    ma quell'espressione è univoca (22/11*2=4)
    Se la leggi come (22/11) * 2 (come il 99% della gente) si, ma c'è anche chi la legge come 22 / (11 *2) dato che moltiplicazione e divisione hanno pari priorità.
    Ho visto flame assurdi su giochini ambigui come questo. Volevo semplicemente rimarcare che se non esistono regole di precedenza (tipo gli operatori) o l'ordine di apparizione (si opera da sx a dx), sia 4 sia 1 sono risultati validi. Nell'espressione dell'OP la x va valutata prima o dopo la chiamata alla funzione? VC++ la valuta dopo (e qui concordo con oregon dato che la chiamata a funzione ha precedenza più alta di moltiplicazione o divisione anche se l'intera espressione può essere valutata a compile time); gcc la valuta prima (e può essere un bug).
    In ogni caso due compilatori danno due valori diversi e solo perché l'espressione dell'OP è ambigua.
    La morale è: evitare espressioni ambigue.
  • Re: Valore in Output differente da quello aspettato

    Nippolo ha scritto:


    mi sembra che nel tentativo di fornire una spiegazione tu stia ipotizzando una differenza tra C e C++
    E hai capito male. Anzi, proprio il contrario.

    Avevo solamente postato in precedenza la tabella per il C++ e per evitare che si credesse che per il C fosse diverso ho postato anche quella per il C.
    Omettendo che quella frase fosse valida per entrambi i linguaggi (ma lo ritenevo scontato dato che le due pagine erano disponibili per la lettura di tutti).

    Quindi, non solo C++, ma anche C non hanno regole in proposito. Capito adesso?

    Era semplice.
    In ogni caso per giungere ad una risposta definitiva devo ragionarci ancora!
    Beh ... c'è poco da ragionarci ancora secondo me, ma non fa mai male ragionare.
  • Re: Valore in Output differente da quello aspettato

    shodan ha scritto:


    ma quell'espressione è univoca (22/11*2=4)
    Se la leggi come (22/11) * 2 (come il 99% della gente) si, ma c'è anche chi la legge come 22 / (11 *2) dato che moltiplicazione e divisione hanno pari priorità.
    Ho visto flame assurdi su giochini ambigui come questo. Volevo semplicemente rimarcare che se non esistono regole di precedenza (tipo gli operatori) o l'ordine di apparizione (si opera da sx a dx), sia 4 sia 1 sono risultati validi. Nell'espressione dell'OP la x va valutata prima o dopo la chiamata alla funzione? VC++ la valuta dopo (e qui concordo con oregon dato che la chiamata a funzione ha precedenza più alta di moltiplicazione o divisione anche se l'intera espressione può essere valutata a compile time); gcc la valuta prima (e può essere un bug).
    In ogni caso due compilatori danno due valori diversi e solo perché l'espressione dell'OP è ambigua.
    La morale è: evitare espressioni ambigue.
    Sul fatto che adottare norme di buona programmazione ci consente di evitare rogne del genere siamo tutti d'accordo, ma qui la questione è definire precisamente quali sono i confini dell'ambiguità.

    Riguardo all'espressione 22/11*2 il risultato in C/C++ è solo 4, visto che qui intervengono esclusivamente le regole di precedenza e associatività degli operatori (che sono ben definite dal linguaggio) e nulla conta l'ordine di valutazione degli operandi (che al contrario non è definito dallo standard).

    Riguardo invece alla maggiore affidabilità di VC sottolineata da te e @oregon ho qualche dubbio, nel senso che non sono tanto sicuro che il concetto di precedenza applicato alla chiamata a funzione sia quello da voi ipotizzato. Consideriamo per esempio il seguente codice:
    #include <stdio.h>
    
    int fun(int x)
    {
        printf("fun(%d)\n", x);
        return x;
    }
    
    int main()
    {
        int a = 3;
        int b = 3;
    
        int c = ++a + fun(a);
        printf("c=%d\n\n", c);
    
        int d = fun(b) + ++b;
        printf("d=%d\n\n", d);
    
        return 0;
    }
    Io con gcc ottengo il seguente output:
    fun(4)
    c=8
    
    fun(3)
    d=7
    
    
    Process returned 0 (0x0)   execution time : 0.019 s
    Press any key to continue.
    Stando al vostro ragionamento la chiamata a funzione ha la priorità sull'incremento prefisso e quindi con VC dovrebbe risultare c=d, giusto?
    Io invece prevedo che otterrete un output simile al mio, ma invertito, in quanto qui non entra in gioco la precedenza degli operatori, ma solo l'ordine di valutazione degli operandi che come tu stesso hai detto risulta essere da sinistra a destra in gcc e da destra a sinistra in VC.
    Fatemi sapere.
Devi accedere o registrarti per scrivere nel forum
21 risposte