2014-12-05 20 views
5

Sto cercando di imparare le basi di C/C++ in questo momento. Sto seguendo un corso su Lynda.comPrincipiante qui: risultati diversi su PC e MAC. Perché?

Le mie domande trattano una sequenza di codice del capitolo 4 "Macro avvertenze dal Corso C/C++ Essential Training". Ho seguito tutte le procedure di configurazione per ottenere correttamente Xcode ed Eclipse su Mac ed Eclipse su PC. Quando eseguo questo codice su MAC e PC ottengo risultati diversi. Sto solo cercando di capire perché questo sta accadendo e cosa posso fare per ottenere lo stesso risultato su entrambi.

Ecco il codice:

// working.c by Bill Weinman <http://bw.org/> 

#include <stdio.h> 
#define MAX(a, b) ((a) > (b) ? (a) : (b)) 

int increment() { 
    static int i = 42; 
    i += 5; 
    printf("increment returns %d\n", i); 
    return i; 
} 

int main(int argc, char ** argv) { 
    int x = 50; 
    printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment())); 
    printf("max of %d and %d is %d\n", x, increment(), MAX(x, increment())); 
    return 0; 
} 

Su un PC ottengo questo risultato:

increment returns 47 
increment returns 52 
max of 50 and 52 is 50 
increment returns 57 
increment returns 62 
increment returns 67 
max of 50 and 67 is 62 

su un Mac (sia Xcode ed Eclipse) ottengo questo risultato:

increment returns 47 
increment returns 52 
increment returns 57 
max of 50 and 47 is 57 
increment returns 62 
increment returns 67 
increment returns 72 
max of 50 and 62 is 72 

Perché sta succedendo questo e cosa posso fare per assicurarmi che i risultati siano gli stessi?

+1

BTW: L'IDE non significa nulla, il compilatore esatto e le opzioni che gli si assegnano, in quasi tutti i casi determinano l'ordine. Anche se in teoria potrebbe cambiare su ogni esecuzione del programma. – Deduplicator

+1

@AdrianoRepetti quasi sicuramente un dup, ma dato che ho una risposta a questa domanda, non voglio chiuderlo con un martello. –

risposta

8

Hai qui risultati non specificati.

L'ordine di valutazione entro printf() non è definito. Dopo aver effettuato più chiamate increment() all'interno della stessa stampa, non si sa mai quale prima viene eseguita per prima e come vengono valutate.

2

Ci sono due problemi qui.

Si sta facendo affidamento su qualsiasi cosa il compilatore scelga per valutare gli argomenti su printf(). Le affermazioni valutate prima modificano i valori delle dichiarazioni successive. Sposta le chiamate increment() dall'elenco degli argomenti. Memorizza invece i risultati di increment() in variabili e passa tali variabili a printf().

Inoltre, l'espansione macro di MAX può causare la valutazione di uno o due argomenti una o due volte. Quindi, anche con lo stesso sistema operativo e il compilatore, puoi ottenere risultati scomodi. Per risolvere questo problema, fare lo stesso che ho suggerito per la memorizzazione dei risultati dell'incremento(). Passa quelle variabili a MAX().

6

L'ordine in cui vengono valutati tutti gli elementi di un'espressione completa non è definito. Tutto ciò che è richiesto è che ogni sottoespressione abbia i suoi operandi completamente valutati prima di essere valutati. Nel caso di una chiamata di funzione, gli argomenti possono essere valutati in qualsiasi ordine e infatti un argomento può essere solo parzialmente valutato al momento in cui un altro argomento viene valutato completamente.

In primo luogo, cerchiamo di espandere la macro:

printf("max of %d and %d is %d\n", x, 
            increment(), 
            ((x) > (increment()) ? (x) : (increment())); 

(Ops, c'è un altro problema qui:. Se increment() è più grande di x allora viene chiamato di nuovo fare il MAX macro una funzione invece così gli argomenti sono valutato solo una volta!)

Tutte le sequenze seguenti sono possibili. Ometto la valutazione di x qui perché non cambia.

  • Il secondo argomento increment() viene valutata, seguita da x > increment(), infine seguita da qualunque ?: operando sia selezionata.(Probabilmente è la sequenza che ti aspettavi.)
  • x > increment() viene valutato, seguito dall'opzione ?: selezionata, infine seguita dal secondo argomento increment().
  • x > increment() viene valutato, seguito dal secondo argomento increment(), infine seguito dall'opzione ?: selezionata.

Questi possono portare a risultati diversi e sono tutti una corretta interpretazione del codice.

Quando si chiamano più funzioni in una singola espressione completa, è necessario assicurarsi che queste funzioni non abbiano effetti collaterali o che gli effetti collaterali di ciascuna funzione non modificino il comportamento di una qualsiasi delle altre funzioni. Altrimenti, la compilazione su un compilatore diverso (o una versione diversa dello stesso compilatore!) Potrebbe cambiare il risultato.

Come esempio aggiuntivo, anche l'espressione dall'aspetto semplice increment() > increment() ha un risultato non specificato, perché l'ordine in cui gli operandi vengono valutati non è definito; se l'operando di sinistra viene valutato per primo, il risultato sarà falso, altrimenti sarà vero.

Nell'esempio più complicato ((a + b) * (c + d)) il compilatore può valutare a, b, c e d in qualsiasi ordine che piace. Tutto ciò che è necessario è che a e b deve essere valutato prima a + b può essere, c e d deve essere valutato prima c + d può essere, e a + b e c + d deve essere valutato prima dell'operatore finale * può essere.

Problemi correlati