ProgrammatieLead C Developer, Systeem Programmeur

Hoe worden bijeffecten van functieargumenten in de C-taal geïmplementeerd? Wat is de volgorde van berekening van argumenten, en welke onverwachte problemen kunnen zich voordoen?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

In de C-taal is de volgorde van berekening van functieargumenten niet gedefinieerd door de standaard (tot en met C99). Argumenten kunnen van links naar rechts, van rechts naar links of in een andere volgorde worden berekend (afhankelijk van de compiler of architectuur).

  • Alle expressies/bijeffecten in de argumenten moeten zijn voltooid voordat de functie wordt aangeroepen, maar er is geen garantie dat ze in een bepaalde volgorde worden uitgevoerd.
  • Dit betekent dat het gebruik van variabelen met waarde-aanpassingen in meerdere argumenten een potentiële bron van ongedefinieerd gedrag kan zijn of gewoon verschillen tussen architecturen kan veroorzaken.

Voorbeeld

void fn(int a, int b) { /* ... */ } int x = 1; fn(x++, x++); // de volgorde van berekening van x++ en x++ is niet gedefinieerd!

Misleidende vraag

"In welke volgorde worden functieargumenten in C berekend en kan ik op dit gedrag vertrouwen bij het schrijven van code?"

Een veelgemaakte fout is om te denken dat argumenten van links naar rechts worden berekend (in overeenstemming met expressies). In de praktijk wordt elke functieverzoek gecompileerd op basis van de keuze van de compiler (en platform).

void foo(int a, int b, int c); int x = 1; foo(x++, x++, x++); // het resultaat hangt af van de volgorde van berekening van de argumenten

Het echte antwoord: je kunt er niet op vertrouwen — het gedrag is niet gedefinieerd!

Voorbeelden van echte fouten door onwetendheid over de nuances van het onderwerp


Verhaal

In een multi-platform product schreef een programmeur push(stack, stack->size++, data);. Op de meeste platformen werkte alles, maar op één platform werd de grootte van de stack vergroot vóór het doorgeven van gegevens, en op een ander platform daarna. Gegevens werden "verloren" of niet correct geadresseerd, de fout trad zelden op en was erg moeilijk te debuggen.


Verhaal

In de netwerkprotocolbibliotheek werd de loggingfunctie aangeroepen met expressies-argumenten, die statistische tellers incrementeerden. De statistische rapporten werden onjuist gegenereerd: bij verschillende klanten verschilden de indices van de tellers, omdat ze niet in de verwachte volgorde werden uitgevoerd.


Verhaal

In de hardwarebedieningsinterface gaf de initialisatiefunctie pointers en verschuivingen door met incrementele waarden binnen de argumenten (type init(ptr++, cnt++);). Op sommige processors werd de hardware correct geïnitieerd, terwijl er op andere een fout optrad, de oorzaak werd lange tijd in de hardware gezocht, terwijl het probleem in de onjuiste C-code lag.