Wat is de volledige “for”-lussyntaxis in C?

Ik heb een aantal zeer vreemde for-lussen gezien bij het lezen van de code van andere mensen. Ik heb geprobeerd te zoeken naar een volledige syntaxisverklaring voor de for-lus in C, maar het is erg moeilijk omdat het woord “for” in niet-gerelateerde zinnen voorkomt, waardoor het zoeken bijna onmogelijk is voor Google.

Deze vraag kwam bij me op na het lezen van deze threadwaardoor ik weer nieuwsgierig werd.

De forhier:

for(p=0;p+=(a&1)*b,a!=1;a>>=1,b<<=1);

In de middelste toestand staat een komma tussen de twee stukjes code, wat doet deze komma? De komma aan de rechterkant begrijp ik omdat het zowel a>>=1als b<<=1maakt.

Maar wat gebeurt er binnen een lusuitgangsvoorwaarde? Wordt het afgesloten wanneer p==0, wanneer a==1of wanneer beide gebeuren?

Het zou geweldig zijn als iemand me zou kunnen helpen dit te begrijpen en me misschien in de richting van een volledige for-lussyntaxisbeschrijving zou kunnen wijzen.


Antwoord 1, autoriteit 100%

De komma is niet exclusief for-lussen; het is de komma-operator.

x = (a, b);

doe eerst a, dan b, en stel dan x in op de waarde van b.

De syntaxis voor is:

for (init; condition; increment)
    ...

Wat enigszins (waarbij we continueen breakvoorlopig negeren) gelijk is aan:

init;
while (condition) {
    ...
    increment;
}

Dus je for-loop-voorbeeld is (opnieuw negeren van continueen break) gelijk aan

p=0;
while (p+=(a&1)*b,a!=1) {
    ...
    a>>=1,b<<=1;
}

Wat doet alsof het zo is (opnieuw negeren van continueen break):

p=0; 
while (true) {
    p+=(a&1)*b;
    if (a == 1) break;
    ...
    a>>=1;
    b<<=1;
}

Twee extra details van de for-lus die niet in de vereenvoudigde conversie naar een while-lus hierboven zaten:

  • Als de voorwaarde wordt weggelaten, is deze altijd true(resulterend in een oneindige lus tenzij een break, gotoof iets anders breekt de lus).
  • Een continuedoet alsof het een ga naar een label is net voor de increment, in tegenstelling tot een continuein de while-lus die de increment zou overslaan.
  • >

Ook een belangrijk detail over de komma-operator: het is een volgordepunt, zoals &&en ||(daarom kan ik het opsplitsen in scheid uitspraken en laat de betekenis intact).


Wijzigingen in C99

De C99-standaard introduceert een aantal nuances die niet eerder in deze uitleg zijn genoemd (wat erg goed is voor C89/C90).

Allereerst zijn alle lussen op zichzelf staande blokken. Effectief,

for (...) { ... }

is zelf gewikkeld in een paar bretels

{
for (...) { ... }
}

De standaard zegt:

ISO/IEC 9899:1999 §6.8.5 Iteratieverklaringen

¶5 Een iteratie-instructie is een blok waarvan het bereik een strikte subset is van het bereik van zijn
omsluitend blok. Het luslichaam is ook een blok waarvan het bereik een strikte subset is van het bereik
van de iteratieverklaring.

Dit wordt ook beschreven in de Rationale in termen van de extra set beugels.

Ten tweede kan het init-gedeelte in C99 een (enkele) aangifte zijn, zoals in

for (int i = 0; i < sizeof(something); i++) { ... }

Nu komt het ‘blok gewikkeld rond de lus’ goed tot zijn recht; het verklaart waarom de variabele iniet toegankelijk is buiten de lus. U kunt meer dan één variabele declareren, maar ze moeten allemaal van hetzelfde type zijn:

for (int i = 0, j = sizeof(something); i < j; i++, j--) { ... }

De standaard zegt:

ISO/IEC 9899:1999 §6.8.5.3 De for-verklaring

De verklaring

for ( clause-1 ; expression-2 ; expression-3 ) statement

gedraagt ​​zich als volgt: De expressie expression-2 is de controlerende expressie die is
geëvalueerd vóór elke uitvoering van de lusbody. De uitdrukking expressie-3 is
geëvalueerd als een ongeldige expressie na elke uitvoering van de lustekst. Als clausule-1 een . is
declaratie, is het bereik van alle variabelen die het declareert de rest van de declaratie en
de hele lus, inclusief de andere twee expressies; het wordt bereikt in de volgorde van uitvoering
vóór de eerste evaluatie van de controlerende uitdrukking. Als clausule-1 een uitdrukking is, is het
geëvalueerd als een ongeldige uitdrukking vóór de eerste evaluatie van de controlerende uitdrukking.133)

Zowel clausule-1 als uitdrukking-3 kunnen worden weggelaten. Een weggelaten uitdrukking-2 wordt vervangen door a
constante niet nul.

133)Clausule-1 specificeert dus de initialisatie voor de lus, waarbij mogelijk een of meer variabelen worden gedeclareerd voor gebruik in
de lus; de controlerende uitdrukking, uitdrukking-2, specificeert een evaluatie die vóór elke iteratie wordt gemaakt,
zodanig dat de uitvoering van de lus doorgaat totdat de uitdrukking gelijk is aan 0; en uitdrukking-3
specificeert een bewerking (zoals ophogen) die na elke iteratie wordt uitgevoerd.


Antwoord 2, autoriteit 6%

De komma scheidt eenvoudig twee uitdrukkingen en is overal geldig in C waar een normale uitdrukking is toegestaan. Deze worden in volgorde van links naar rechts uitgevoerd. De waarde van de meest rechtse uitdrukking is de waarde van de algemene uitdrukking.

forlussen bestaan ​​uit drie delen, die elk ook leeg kunnen zijn; één (de eerste) wordt aan het begin uitgevoerd en één (de derde) aan het einde van elke iteratie. Deze onderdelen initialiseren en verhogen meestal respectievelijk een teller; maar ze kunnen alles doen.

Het tweede deel is een testdie aan het begin van elke uitvoering wordt uitgevoerd. Als de test falseoplevert, wordt de lus afgebroken. Dat is alles.


Antwoord 3, autoriteit 4%

De C-stijl voor lus bestaat uit drie uitdrukkingen:

for (initializer; condition; counter) statement_or_statement_block;
  • De initialisatie wordt één keer uitgevoerd, wanneer de lus begint.
  • De voorwaarde wordt vóór elke iteratie gecontroleerd. De lus loopt zolang deze evalueert naar waar.
  • De teller loopt één keer na elke iteratie.

Elk van deze delen kan een uitdrukking zijn die geldig is in de taal waarin u de lus schrijft. Dat betekent dat ze creatiever kunnen worden gebruikt. Alles wat je van tevoren wilt doen, kan in de initialisatie gaan, alles wat je tussendoor wilt doen, kan in de conditie of de teller gaan, tot het punt waarop de lus geen body meer heeft.

Om dat te bereiken, is de komma-operator erg handig. Hiermee kunt u uitdrukkingen aan elkaar koppelen om een ​​enkele nieuwe uitdrukking te vormen. Meestal wordt het op die manier gebruikt in een for-lus, de andere implicaties van de komma-operator (bijv. overwegingen bij het toewijzen van waarden) spelen een ondergeschikte rol.

Ook al kun je slimme dingen doen door syntaxis creatief te gebruiken – ik zou er afstand van houden totdat ik een echtgoede reden vind om dit te doen. Het spelen van codegolf met for-loops maakt code moeilijker te lezen en te begrijpen (en te onderhouden).

De wikipedia heeft ook een mooi artikel over de for-lus.

Other episodes