Nel linguaggio C l'ordine di calcolo degli argomenti di una funzione non è definito dagli standard (fino a C99 incluso). Gli argomenti possono essere calcolati da sinistra a destra, da destra a sinistra o in qualsiasi altro ordine (a discrezione del compilatore o dell'architettura).
void fn(int a, int b) { /* ... */ } int x = 1; fn(x++, x++); // l'ordine di calcolo di x++ e x++ non è definito!
"In quale sequenza vengono calcolati gli argomenti di una funzione in C e ci si può fidare di questo quando si scrive codice?"
Un errore comune è pensare che gli argomenti vengano calcolati da sinistra a destra (per analogia con le espressioni). In pratica, ogni chiamata di funzione viene compilata a discrezione del compilatore (e della piattaforma).
void foo(int a, int b, int c); int x = 1; foo(x++, x++, x++); // il risultato dipende dall'ordine di calcolo degli argomenti
La vera risposta è: non ci si può fidare — il comportamento non è definito!
Storia
In un prodotto multi-piattaforma, un programmatore ha scritto
push(stack, stack->size++, data);. Su la maggior parte delle piattaforme tutto funzionava, ma su una il size dello stack aumentava prima della trasmissione dei dati, mentre su un'altra dopo. I dati "andavano persi" o venivano indirizzati in modo errato, l'errore si manifestava raramente ed era molto difficile da debug.
Storia
In una libreria di protocollo di rete, la funzione di logging veniva chiamata con espressioni-argomenti che incrementavano i contatori statistici. I report statistici venivano generati in modo errato: diversi client avevano indici di contatori diversi, poiché venivano eseguiti in un ordine non previsto.
Storia
Nella gestione dell'hardware, la funzione di inizializzazione passava puntatori e offset con incremento all'interno degli argomenti (tipo
init(ptr++, cnt++);). Su alcune CPU, l'hardware veniva inizializzato correttamente, mentre su altre si verificava un crash, la causa è stata a lungo cercata nell'hardware, anche se il problema era nel codice C non corretto.