W języku C kolejność obliczania argumentów funkcji nie jest zdefiniowana przez standard (do C99 włącznie). Argumenty mogą być obliczane od lewej do prawej, od prawej do lewej lub w dowolnej innej kolejności (według uznania kompilatora lub architektury).
void fn(int a, int b) { /* ... */ } int x = 1; fn(x++, x++); // kolejność obliczania x++ i x++ nie jest określona!
"W jakiej kolejności obliczane są argumenty funkcji w C i czy można na to polegać przy pisaniu kodu?"
Częstym błędem jest założenie, że argumenty są obliczane od lewej do prawej (analogicznie do wyrażeń). W praktyce każde wywołanie funkcji jest kompilowane według uznania kompilatora (i platformy).
void foo(int a, int b, int c); int x = 1; foo(x++, x++, x++); // wynik zależy od kolejności obliczania argumentów
Prawdziwa odpowiedź: nie można polegać — zachowanie nie jest określone!
Historia
W wieloplatformowym produkcie programista napisał
push(stack, stack->size++, data);. Na większości platform wszystko działało, ale na jednej rozmiar stosu zwiększał się przed przekazaniem danych, na innej — po. Dane "traciły się" lub były adresowane niepoprawnie, błąd występował rzadko i był bardzo trudny do debugowania.
Historia
W bibliotece protokołu sieciowego funkcja logowania była wywoływana z wyrażeniami-argumentami, które inkrementowały liczniki statystyczne. Raporty statystyczne były generowane nieprawidłowo: u różnych klientów indeksy liczników różniły się, ponieważ nie były wykonywane w oczekiwanej kolejności.
Historia
W interfejsie zarządzania sprzętem funkcja inicjalizacji przekazywała wskaźniki i przesunięcia z inkrementem wewnątrz argumentów (typ
init(ptr++, cnt++);). Na niektórych procesorach sprzęt był inicjowany poprawnie, a na innych występowały błędy, których przyczynę długo szukano w sprzęcie, mimo że problem tkwił w niepoprawnym kodzie C.