2009-03-07 14 views
52

Ok, sono a conoscenza del fatto che lo standard impone che un'implementazione C++ possa scegliere in quale oggetto vengono valutati gli argomenti di una funzione, ma esistono implementazioni che effettivamente "sfruttano" questa in uno scenario in cui avrebbe effettivamente influenzato il programma?Compilatori e ordine delle argomentazioni di valutazione in C++

Classic Esempio:

int i = 0; 
foo(i++, i++); 

Nota: non sto cercando qualcuno a dirmi che l'ordine di valutazione non può essere invocata, io sono ben consapevole di questo. Mi interessa solo sapere se alcuni compilatori effettivamente valutino da un ordine da sinistra a destra, perché la mia ipotesi sarebbe che se facessero un sacco di codice scritto male si romperebbe (giustamente, ma probabilmente si lamenterebbero ancora).

+0

Provalo tu stesso con diversi compilatori? – strager

+0

Mi sono posto la stessa domanda mentre implementavo un interprete per un sottoinsieme di C++. Uff. –

+6

Si noti che 'foo (i ++, i ++)' richiama il comportamento non definito, perché 'i' viene incrementato di più di uno senza alcun punto di sequenza intermedio. – Nawaz

risposta

49

Dipende dal tipo di argomento, dalla convenzione di chiamata della funzione chiamata, dall'architettura e dal compilatore. Su un x86, la convenzione di chiamata Pascal valuta gli argomenti da sinistra a destra mentre nella convenzione di chiamata C (__cdecl) è da destra a sinistra. La maggior parte dei programmi eseguiti su piattaforme multiple tiene conto delle convenzioni di chiamata per evitare sorprese.

C'è un bel article sul blog di Raymond Chen se sei interessato. Si consiglia inoltre di dare un'occhiata alla sezione Stack and Calling del manuale GCC.

Modifica: Fintanto che stiamo dividendo i capelli: La mia risposta considera questo non come una domanda di lingua ma come una piattaforma. Lo standard di lingua non garantisce o preferisce uno rispetto all'altro e lo lascia come non specificato. Nota la formulazione. Non dice che questo non è definito. Non specificato in questo senso significa qualcosa su cui non puoi contare, comportamento non portatile. Non ho la C spec/progetto a portata di mano ma dovrebbe essere simile a quella del mio n2798 progetto (C++)

alcuni altri aspetti e le operazioni della macchina astratta sono descritti nella presente norma internazionale come non specificata (per esempio, ordine di valutazione degli argomenti per una funzione). Ove possibile, questo standard internazionale definisce un insieme di comportamenti consentiti. Questi definiscono gli aspetti non deterministici della macchina astratta. Un'istanza della macchina astratta può quindi avere più di una possibile sequenza di esecuzione per un dato programma e un dato input.

+11

Per essere chiari, pascal/cdecl decide se gli argomenti sono * passati * da sinistra a destra o da destra a sinistra - possono ancora essere * valutati * in qualsiasi ordine. (Anche se a causa della pressione del registro è probabile che vengano valutati nello stesso ordine in cui sono passati.) –

+8

Errore: gli argomenti C vengono inseriti nello stack da destra a sinistra. Ma l'ordine in cui vengono valutati non è definito. –

+1

@Martin York: quando ho detto che l'ordine è ben definito? – dirkgently

1

L'ultima volta che ho visto differenze tra le era VS2005 e GCC 3.x su un hardware x86 nel 2007. Quindi è (era?) Una situazione molto probabile. Quindi non faccio mai più affidamento sull'ordine di valutazione. Forse è meglio ora.

+0

Oh? È molto bello saperlo. Grazie. Attualmente gli unici compilatori che uso sono VC 08 e ICC 11. Probabilmente dovrei iniziare a testare il mio codice anche in GCC. – RaptorFactor

+2

ICC fa di tutto per essere il più compatibile possibile con VS. Bene gente quelle persone Intel :) –

+0

VS non garantisce nemmeno un ordine di valutazione. Hanno cambiato il modo in cui valutano gli argomenti delle funzioni prima e non c'è motivo per cui non lo farebbero più. Non è qualcosa su cui dovresti fare affidamento. L'eliminazione di sottoespressione comune di – jalf

2

Mi aspetto che la maggior parte dei compilatori moderni tenti di interlacciare le istruzioni calcolando gli argomenti, dato che sono richiesti dallo standard C++ per essere indipendenti e quindi privi di interdipendenze. Fare ciò dovrebbe aiutare a mantenere piene le unità di esecuzione della CPU profondamente pipeline e quindi aumentare il throughput. (Almeno mi sarei aspettato che un compilatore che sostiene di essere un compilatore ottimizzato avrebbe fatto in modo che quando sono date flag di ottimizzazione.)

6

Read this

Non è una copia esatta della tua domanda, ma la mia risposta (e un pochi altri) copre anche la tua domanda.

Ci sono ottime ragioni di ottimizzazione per cui il compilatore potrebbe non scegliere solo da destra a sinistra, ma anche interlacciare.

Lo standard non garantisce nemmeno un ordinamento sequenziale. Lo solo garantisce che quando viene chiamata la funzione, tutti gli argomenti sono stati valutati completamente.

E sì, ho visto alcune versioni di GCC fare esattamente questo. Per il tuo esempio, sarebbe stato chiamato foo (0,0), e sarei 2 successivamente. (Non posso darti il ​​numero esatto della versione del compilatore Era un po 'di tempo fa - ma non sarei sorpreso di vedere nuovamente questo comportamento: è un modo efficace per programmare le istruzioni)

+0

è il motivo principale per il riordino dell'ottimizzazione. Ricorda che la valutazione degli argomenti e il passaggio dei parametri possono essere diversi, anche se molti compilatori li trattano in modo identico. Il clang – plinth

3

Tutti gli argomenti sono valutati. Ordine non definito (come da standard). Ma tutte le implementazioni di C/C++ (che io sappia) valutano gli argomenti delle funzioni da da destra a sinistra. MODIFICA: CLang è un'eccezione (vedi commento sotto).

Credo che l'ordine di valutazione da destra a sinistra sia stato molto vecchio (dai primi compilatori C). Certamente prima che il C++ venisse inventato, la maggior parte delle implementazioni del C++ manterrebbe lo stesso ordine di valutazione perché le implementazioni C++ iniziali semplicemente tradotte in C.

Ci sono alcuni motivi tecnici per valutare gli argomenti della funzione da destra a sinistra. Nelle architetture stack, gli argomenti vengono generalmente inseriti nello stack. In C/C++, puoi chiamare una funzione con più argomenti di quelli effettivamente specificati - gli argomenti extra vengono semplicemente ignorati. Se gli argomenti vengono valutati da sinistra a destra e spostati da sinistra a destra, lo slot di stack subito sotto il puntatore dello stack manterrà l'ultimo argomento e non è possibile per la funzione ottenere l'offset di un particolare argomento (perché il numero effettivo di argomenti spinti dipende dal chiamante).

In un ordine push da destra a sinistra, lo slot di stack posto proprio sotto il puntatore dello stack mantiene sempre il primo argomento e lo slot successivo mantiene il secondo argomento, ecc. Gli offset degli argomenti saranno sempre deterministici per la funzione (che può essere scritto e compilato altrove in una biblioteca, separatamente da dove è chiamato).

Ora, l'ordine push da destra a sinistra non richiede un ordine di valutazione da destra a sinistra, ma nei primi compilatori la memoria scarseggia. Nell'ordine di valutazione da destra a sinistra, lo stesso stack può essere utilizzato sul posto (in sostanza, dopo aver valutato l'argomento - che può essere un'espressione o una chiamata funciton!), Il valore di ritorno è già nella posizione corretta sul pila). Nella valutazione da sinistra a destra, i valori degli argomenti devono essere memorizzati separatamente e reinseriti nello stack in ordine inverso.

+0

utilizza la valutazione da sinistra a destra. – Kaiserludi

8

Ho trovato risposta in c++ standards.

Paragrafo 5.2.2.8:

L'ordine di valutazione degli argomenti non è specificato. Tutti gli effetti collaterali delle valutazioni delle espressioni degli argomenti hanno effetto prima che la funzione venga inserita. L'ordine di valutazione dell'espressione postfissa e dell'elenco di espressioni dell'argomento è non specificato.

In altre parole, dipende solo dal compilatore.

+2

Uhm, non risponde alla domanda. – ThomasMcLeod

Problemi correlati