Context:
Logische operatoren && en || zijn geïntroduceerd in C om complexe logische voorwaarden te controleren. Kenmerkend voor hun werking is de ondersteuning voor kortsluitingsevaluatie: de tweede operand wordt niet geëvalueerd als het resultaat al eenduidig kan worden bepaald op basis van de eerste.
Probleem:
Veel programmeurs verwachten dat beide operand altijd worden geëvalueerd, of maken onjuist gebruik van bijeffecten in de tweede operand, in de veronderstelling dat deze noodzakelijkerwijs zal worden uitgevoerd. Dit leidt in de praktijk tot fouten, resource-lekken en onvoorspelbaar gedrag.
Oplossing:
Het begrijpen van het mechanisme van kortsluitingsevaluatie helpt bij het bouwen van veilige constructies, vooral bij het controleren van pointers, resources en bestanden. Het gebruik van bijeffecten aan de rechterkant van de expressie is alleen te rechtvaardigen als dit bewust wordt gedaan. Voorbeeld van een veilige controle:
if (ptr && ptr->field) { /* ... */ }
Belangrijke kenmerken:
Zal de expressie f() worden uitgevoerd in het fragment: if (0 && f())
Nee, de functie f() zal niet worden aangeroepen, omdat het resultaat al duidelijk is – de expressie is onwaar, verdere evaluatie is nutteloos.
En in de volgende notatie: if (1 || f())?
Weer zal f() niet worden aangeroepen: het resultaat is al waar na de eerste operand.
Kan ik de operatoren && en || gebruiken om de volgorde van uitvoering van functies met bijeffecten te beheren?
Technisch gezien kan dat, maar dergelijke controle leidt tot onleesbare en onbetrouwbare code. Het is beter om de volgorde van functieaanroepen expliciet te beschrijven, in plaats van op het gedrag van kortsluiting te vertrouwen voor bijeffecten.
if (flag || process()) { // ... }
Het proces wordt nooit aangeroepen als flag waar is.
Voordelen:
Nadelen:
if (!flag) process();
Voordelen:
Nadelen: