Knuppel in het "C" hoenderhok => Goto/Return

@Rew, je snapt dat het een voorbeeldje was he. ;)

@Ohm pi, Ik ben het deels met je eens. Ja het is zo dat het in een hobby sfeer niet zoveel uit maakt. Dan is het hooguit voor jezelf dat je het later ook nog snapt. Het wordt pas echt belangrijk als je samen gaat werken of je code later aan iemand anders moet kunnen geven zodat die persoon er verder mee kan.

Maar ik zelf probeer commentaar juist te vermijden. Als je code duidelijk is opgebouwd dan heb je praktisch geen commentaar nodig. Nadeel van commentaar is dat het altijd achter loopt op de code zelf. Ook bij kopiëren en plakken gaat dit vaak fout.

Als beginner en hobbyist, inderdaad who cares? Zolang je maar plezier beleeft aan je hobby is het goed.

Wat voor Blackdog wellicht nog goed is om te weten: Variables die je aanmaakt bestaan alleen in hun eigen context!!! (Er zijn wat uitzonderingen, maar die laat ik even achterwegen)

[Bericht gewijzigd door hardbass op dinsdag 21 juni 2022 18:43:48 (11%)

PE2BAS

Op 21 juni 2022 18:28:01 schreef ohm pi:
Is het voor jezelf, dan zou ik me over die goto-statement geen zorgen maken.

Volgens mij begint bij mij nu OOK het kwartje te vallen. Wat blackdog in de eerste instantie "goto" noemt blijkt "functie-aanroepen" te zijn. Dat deed ie vroeger met GOTO. Zijn vraag blijkt niet over goto te gaan, maar over structuur aanbrengen door stukjes code af te zonderen.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
blackdog

Golden Member

Hi,

deKees, op jouw opmerking kom ik later nog terug even wat laten indalen...

ohm pi, klopt dit is voor mij zelf, vooral meetinstrumentjes die ik bouw en nog wil bouwen.
Niets zakelijks, het komt niet meer voor in mijn werk, dat ik logische schaklingen opbouw voor een klant.

Rew, welkom bij de club! ;)

Maar laten we hopelijk voor mij naar het volgende leermomentje gaan.
rew geeft aan dat als void Action1() is aangeroepen in de loop, dat ik dan verderop in de als de eerste keer is afhehandeld dit in de loop niet nog een keer kan doen.
Het lijkt mij logisch dat je void Action1() niet in void Action1() aanroep.

Als de code is gecompileerd kan er dan, of wordt er dan niet meer bijgehouden wanneer void Action1() is aangeroepen op welke plek?

Als het dus bij de Arduino C versie niet kan wat gebruik je dan als je een stukje code eventueel meerdere keren zou willen aanroepen?

Dank en groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.
big_fat_mama

Zie Paulinha_B

Heerlijk citaat uit Lewis Carroll, de laatste regel is cruciaal:

Begin at the beginning.
Go on till the end.
Then stop.

Zo was het in assembler, en ook nog min of meer in Basic. Naarmate de talen evolueerden ging het minder en minder lineair. (Ik denk dat dat het essentiele probleem is van Bram @blackdog: met zijn taalhandicap (waar hij tussen haakjes voorbeeldig mee omgaat, ik blijf dat waarderen en bewonderen!) ziet hij een programma als een lineaire opeenvolging van instructies, en zo was het inderdaad ooit. Vandaag dus niet meer.

(en al helemaal niet meer in "object oriented" code, daar beschrijft de programmeuse (m/v/x) een aantal objecten [balletje, muur, palet, ...] die elks hun eigenschappen hebben)

wat gebruik je dan als je een stukje code eventueel meerdere keren zou willen aanroepen?

Zoals reeds meermaals gesteld: maak er een functie van. Ik probeer even een belachelijk voorbeeld te geven in pseudo-code:

code:


def functie(frituur)(temp, seconden)
 % code
 % code
 return 'Gaar!'
 einde functiedefinitie

frituur_bitterballen: frituur(180,300)
frituur_inktvis: frituur(160,480)

Dus eerst wordt de functie gedefinieerd, inclusief de mee te geven parameters, en daarna kan ze vanuit het "hoofdprogramma" worden aangeroepen naargelang nodig.

hoe beter de vraag geschreven, zoveel te meer kans op goed antwoord

Op 21 juni 2022 13:58:22 schreef bprosman:

c code:


int main () {

   /* local variable definition */
   char grade = 'B';

   switch(grade) {
      case 'A' :
         printf("Excellent!\n" );
         break;
      case 'B' :
      case 'C' :
         printf("Well done\n" );
         break;
      case 'D' :
         printf("You passed\n" );
         break;
      case 'F' :
         printf("Better try again\n" );
         break;
      default :
         printf("Invalid grade\n" );
   }
   
   printf("Your grade is  %c\n", grade );

Daarom hou ik zo van Delphi en Pascal:

code:


case Grade of
   'A': Writeln('Excellent!');
   'B': ;
   'C': Writeln('Well done');
   'D': Writeln('You passed');
   'F': Writeln('Better try again!');
   else Writeln('Invalid grade');
end;

Op 21 juni 2022 19:14:28 schreef blackdog:
Het lijkt mij logisch dat je void Action1() niet in void Action1() aanroep.

Als de code is gecompileerd kan er dan, of wordt er dan niet meer bijgehouden wanneer void Action1() is aangeroepen op welke plek?

Haha ik wist dat dit ging komen. Dit kan dus wel! Dat heet recursie of in het Engels recursion https://www.tutorialspoint.com/cprogramming/c_recursion.htm

Nu wordt het wel ingewikkeld, dit kan tot zekere mate. Op den duur is je stack op en dan krijg je een zogenaamde stack overflow error. Daar is het forum 'stack overflow' ook naar vernoemd.

Dit is gelijk een gateway naar je 2e vraag, hoe weet het programma waar hij is gebleven. (De korte versie, anders wordt het te gek.)

Je programma gebruikt een deel van de ram als stack. Dit is niets anders dan een grote stapel waar je dingen op kan zetten en dingen af kan halen. Iedere keer dat je programma naar een functie toe springt, voegt hij een pointer toe op de stack. Deze pointer beschrijft waar hij was gebleven in de vorige functie. Wanneer je functie is afgelopen dan haalt hij deze pointer weer van de stack. Zo weet hij altijd waar hij is gebleven.

Deze stack kan je ook zien als je gaat debuggen. Dat noemt men de callstack. In de praktijk wordt er veel meer op de stack gezet. Maar dat is nu niet relevant.

Ik moet nu even weg, als ik morgen wat meer tijd heb kan ik een betere uitleg schrijven. (Al vraag ik me af of je je er nu al druk om moet maken :))

PE2BAS

rew geeft aan dat als void Action1() is aangeroepen in de loop, dat ik dan verderop in de als de eerste keer is afgehandeld dit in de loop niet nog een keer kan doen.

Jawel, je kunt Action1() zo vaak aanroepen als je wilt in de C/C++ versie.

rew verwijst hier naar de vertaling met goto's in het voorbeeld van hardbass. En in die vertaling kan het inderdaad niet door de goto return_action1. Die vertaling is dus niet helemaal accuraat. In werkelijkheid staat daar een return instruktie die terugspringt naar waar hij vandaan kwam. En de goto is feitelijk een gosub zodat het return addres bewaard blijft.

Hierbij een betere vertaling van de hardbass code:

code:


main:
  gosub action1;
  gosub action2;
(END OF PROGRAM)

action1:
  printf("Hallo wereld");
  return;

action2:
  printf("Hello world");
  return;

Op 21 juni 2022 19:22:49 schreef Hoeben:
[...]

Daarom hou ik zo van Delphi en Pascal:

code:


case Grade of
   'A': Writeln('Excellent!');
   'B': ;
   'C': Writeln('Well done');
   'D': Writeln('You passed');
   'F': Writeln('Better try again!');
   else Writeln('Invalid grade');
end;

Als je dat perse wilt mag die break ook op dezelfde regel hoor, maar je hebt het niet helemaal begrepen, want in jouw voorbeeld wordt er volgens mij niets geprint bij een B.

Misschien was er een goede reden dat ik jou nooit software heb laten schrijven ;)

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
blackdog

Golden Member

Hi,

Ik begrijp nu denk ik het springen naar void Action1() enz.
En de volgende stap is dan de limieten leren kennen van die stappen/springen/terugkeren.

rew zegt dat je eigenlijk maar 1x naar void Action1() kan springen een terug keren in je loop en hardbass zegt dat het wel kan.
Er zijn dus duidelijk voorwaarde aan het gebruik er van en dat wil ik graag helder hebben, zo plak ik dat dan in mijn geheugen, zoiets als hapklare brok.

Taalprobleem
Mijn Nederlands rammelt aan alle kanten, op advies van bprosman ben ik de meeste stukjes die ik type in MS word aan het scannen op fouten en de meeste bagger gaat er dan wel uit.
Maar alsnog bouw ik zinnen vaak om, dit omdat het niet mooi loopt en er blijven altijd fouten in zitten, dit omdat MS wordt niet begrijpt wat ik wil zeggen. ;)
big_fat_mama dank voor het compliment, ik wil graag begrepen worden, dus doe ik er moeite voor.

Veel wordt in mijn brein als ik het onder de knie heb als eensoort plaatje opgelsagen, dat is natuurlijk niet helemaal hoe het werkt, maar het geeft in ieder geval een indruk.
Rob een collega van mij zij toen hij voor de zoveelste keer zag, dat ik schreef: De SQ20 versterker heb ik megenonen voor reparatie, Bram het is meegenomen met dubbel ee.
Daarna "vastgezet" in mijn hoofd en niet een keer meer fout gedaan. Bureaublad schrijf ik nooit fout, dit zit op de zelfde manier in mijn hoofd verankerd.
Het vreemde is, dat ik met lineaire elektronica ik heel veel variabelen bij zeg het gebruik van opamps direct klaar heb in mijn hoofd, maar de lijstjes hier naast mij, die behandelen hoe je met de letter "s" omgaat aan het einde van een woord, is een drama voor mij om dat goed in mijn hoofd te planten.

Duidelijkheid gedrag van de sprong naar buiten de loop en terug
Dus ik wil graag weten hoe het zit met het springen naar b.v. void Action1() en voor de duidelijkheid, ik werk alleen met Arduino soorten.
Net als dat ik geen spaghetti laat zien in mijn elektronica projecten, wil ik dit ook niet in de software doen.
Het moet juist duidelijker worden voor mij en ik begrijp ook dat je sommige trucjes met mate zal moeten toepassen.

Dank en groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Op 21 juni 2022 19:38:01 schreef hardbass:
[...]

Haha ik wist dat dit ging komen. Dit kan dus wel! Dat heet recursie of in het Engels recursion https://www.tutorialspoint.com/cprogramming/c_recursion.htm

Voor de C-programmeurs onder ons: :+

code:


int main()
{ 
   main();
}

Op 21 juni 2022 20:28:55 schreef SparkyGSX:
Misschien was er een goede reden dat ik jou nooit software heb laten schrijven ;)

Het komt op het testen van geschreven software aan. Ik heb liever een goede softwaretester dan een -schrijver. De tester haalt de fouten er wel uit.

[Bericht gewijzigd door ohm pi op dinsdag 21 juni 2022 20:43:30 (33%)

big_fat_mama

Zie Paulinha_B

Dus ik wil graag weten hoe het zit met het springen naar b.v. void Action1()

Het is echt een taalkwestie. Men springt niet naar een functie, men roept ze aan. Om maar even door te gaan op mijn bewust absurde voorbeeld:

De chef springt niet naar de friteuse om aan de knoppen te draaien. De chef roept naar de assistente: "Marian, zet friteuse 4 even gauw op 170 graden, er komt een hoop kaaskroketjes aan". Dan is het aan Marian om te laten weten "okee, doen we" dan wel "sorry, chef, friteuse 4 is helemaal niet beschikbaar vandaag" dan wel "okee chef, nu op 170 graden, zeg maar hoeveel we erin kieperen".

Marian is dus de functie, in dit geval - met alle persoonlijk respect, uiteraard.

hoe beter de vraag geschreven, zoveel te meer kans op goed antwoord
PE9SMS

Special Member

De program counter maakt een adres sprong, dus zo gek is dat springen niet.

This signature is intentionally left blank.
fatbeard

Honourable Member

@b_f_m: mooie analogie.
Ik vrees echter dat ergens nog een klein stukje begripsverwarreling blijft bestaan, dus hier is mijn kennis over dit subject (ik heb een dikke 12 jaar mijn brood verdiend met programmeren in vele talen):

De instructie goto XYZ bestaat in veel programmertalen en dialecten, maar betekent -voorzover mij bekend- altijd hetzelfde: 'laat alles uit je handen vallen en ga verder op plek XYZ'.
Er bestaat dus geen 'herinnering' aan dat wat er gaande was, en je kunt daar dus ook niet mee verder zonder een hele grote kist aan omslachtig gedoe (die de duidelijkheid van je programma niet ten goede gaat komen).

Omdat het vaak herhalen van hetzelfde stukje code (maar dan op een andere plek) schering en inslag is in vrijwel elk programma heeft men daar de 'procedure call' (ook bekend als subroutine) voor uitgevonden, deze is in veel talen bekend als gosub XYZ. Dat betekent zoveel als 'maak een notitie van waar je mee bezig bent en ga dan verder op plek XYZ, als je daar klaar bent kun je verder gaan met waar je mee bezig was.

Een mooie en enigzins elegante constructie, maar het betekent wel dat er een soort draaiboek voor de acties in XYZ moet worden gemaakt.
Dat draaiboek gemaak je met void XYZ() {...}; , afgesloten met een return en staat bekend onder de naam procedure. De void geeft aan dat het stukje code wat volgt geen resultaat teruggeeft maar alleen wat acties uitvoert. Tussen de haakjes kunnen wat parameters staan om die acties te sturen of verfijnen; het geheel wordt aangeroepen (=uitgevoerd) met het statement XYZ();.

Als je die void vervangt door een datatype (int, real, char etc) definieer je een berekening, bijv: int RESULTAAT() {...; return (6*2+4)}; , dit staat bekend als een function.
Het principiële verschil tussen een procedure en een function (er zijn ook mensen die dat onderscheid niet maken) is dat een procedure geen resultaat terugggeeft en een function wel, parameters zijn bij beide optioneel.

Het gevaar van het mixen van goto en gosub bestaat hierin, dat dat kladblaadje wat gemaakt wordt met gosub alleen gewist wordt als er een return wordt uitgevoerd. Als die return dus door een goto wordt omzeild blijft dat kladblaadje bestaan, en na verloop van tijd crasht dan het programma omdat het kladblok vol raakt...

Een goed begin is geen excuus voor half werk; goed gereedschap trouwens ook niet. Niets is ooit onmogelijk voor hen die het niet hoeven te doen.

Het (enige) voordeel van assembler is dat je een beter begrip krijgt hoe een computer werkt, en wat de programmeertaal en compiler voor je oplossen.

Vrijwel iedere processor werkt gewoon lineair: 1e instructie klaar dan volgende instructie.

Er is een instructie "jump" en daarmee kun je naar een willekeurige andere instructie springen.

En er is een instructie "call". Daarmee spring je ook naar een andere instructie, maar voordat de processor dat doet stopt ie het adres van de instructie NA de call-instructie in het geheugen.

Met de "return" instructie springt te processor dus weer terug naar de instructie volgend op de vorige "call" instructie. En zo kun je makkelijk functies (of subroutines) implementeren.

Op 21 juni 2022 19:14:28 schreef blackdog:

rew geeft aan dat als void Action1() is aangeroepen in de loop, dat ik dan verderop in de als de eerste keer is afhehandeld dit in de loop niet nog een keer kan doen.
Het lijkt mij logisch dat je void Action1() niet in void Action1() aanroep.

Nee, dat ging niet over aanroepen in C. Dat ging over jou constructie in BAT files. Een functie zou zelfs zichzelf mogen aanroepen, al zie ik jou dat nog niet zo snel doen.

code:


int factorial (n)
{
  if (n <= 1) return 1;
  return n * factorial (n-1);
}

Hier kan dat nog relatief makkelijk anders, maar bijvoorbeeld:

code:


float sin (float a)
{
  if (a < 0) return - sin (-a);
  if (a > 2 * PI) return sin (a-2*PI); // voor verbetering vatbaar.
  if (a > PI) return -sin (2*PI - a);
  if (a > PI/2) return sin (PI -a);
  .... reken hier sinus uit, voor hoeken tussen 0 en PI/2;
  return result;
}

Hier is de code zeer makkelijk leesbaar doordat de functie zichzelf aanroept. In de praktijk is dit een library functie waarbij iemand er alles aan gedaan heeft om dat ding zo snel mogelijk te maken. Dat komt de leesbaarheid niet ten goede, maar haalt een paar kleine inefficienties er uit.

Maar goed. Dat is al enigszins geavanceerd.

Ik heb gisteren iemand geadviseerd om ergens een functie van te maken.

Hij had:

code:


  // selecteer kanaal nul
  pinMode (SELA, OUTPUT);
  digitalWrite (SELA, 0);
  pinMode (SELB, OUTPUT);
  digitalWrite (SELB, 0);

  ... doe wat met kanaal nul

  // selecteer kanaal 1 
  pinMode (SELA, OUTPUT);
  digitalWrite (SELA, 1);
  pinMode (SELB, OUTPUT);
  digitalWrite (SELB, 0);
 
  .. doe wat met kanaal 1 

Maar dat kan veel netter:

code:


void kanaal (int n)
{
  pinMode (SELA, OUTPUT);
  digitalWrite (SELA, n & 1);
  pinMode (SELB, OUTPUT);
  digitalWrite (SELB, (n >> 1) & 1);
}


... 
kanaal (0);
// doe wat met kanaal 0
kanaal (1);
// doe wat met kanaal 1...

Nu is die tweede keer pinMode aanroepen onnodig in beide voorbeelden, maar hij had het er voor de zekerheid gewoon in staan. Dus dat heb ik zo gelaten. (ik heb de hardware gemaakt die op basis van de SELA en SELB signalen het juiste kanaal activeert.)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Zo, heb gister avond nog wat uitgetypt maar nog niet op CO gezet. Ik heb expres een hoop details weg gelaten en de focus gelegd op de vraag van Blackdog.

De microcontroller:
Een microcontroller bestaat uit meerdere delen. De relevante delen voor dit verhaal zijn: CPU, RAM en ROM. De ROM is in de praktijk vaak een stukje flash. Sommige processoren kunnen daar ook naar schrijven. Maar dat is voor nu niet relevant. Zoals je wellicht wel weet staat de software in de ROM. Dit is eigenlijk een lange lijst met instructies. De CPU doet niets anders dan een voor een alle instructies uitvoeren. Om een beetje idee te geven, in dit plaatje zie je hoe dit in de ROM staat opgeslagen. In het rode kader staan de adressen en de waardes die in de ROM staan. Als je erg veel geduld hebt kun je een Arduino programmeren op deze manier! Omdat dit natuurlijk vreselijk onhandig is, heeft men de zogenaamde assembly (ASM) taal uitgevonden. Hier zie je voorbeelden van staan in het blauwe kader. Links is de instructie, rechts zijn de parameters. Op iedere regel zie je de vertaling tussen ASM en de waardes die in de ROM staan. Het omzetten van de ASM naar de codes wordt gedaan door de assembler.

Compileren:
Assembly is al een heel stuk makkelijker dan zelf alle hex codes onthouden. Maar zoals je kan zien is zelfs dit nog behoorlijk onhandig om iets mee te maken. Dit gebeurde vroeger wel heel veel. Gelukkig hebben een aantal slimme koppen een nieuwe taal bedacht genaamd C. (Ik sla even dingen als basic over. Dat werkt weer heel anders en zorgt alleen voor verwarring.)
De truc was natuurlijk, hoe krijg je een C programma in de ROM. Als je letterlijk je code erin zou plakken, kan de CPU hier niets mee. Daar is de compiler voor uitgevonden. Deze zet de C code om naar ASM. Zoals je nu zelf wellicht al ziet aankomen. Wanneer je de arduino code 'upload' gebeurt het volgende:
1. De C code wordt gecompileerd naar ASM.
2. De ASM wordt geassembleerd naar HEX.
3. De HEX wordt naar de ROM geschoten.
4. De CPU wordt herstart.

De processor:
De CPU heeft een aantal registers. Deze registers staan dus niet in de RAM, maar zijn extra stukjes geheugen in de CPU zelf. Zoon register is niets anders dan een stukje geheugen waar je een waarde in kan opslaan. Een van deze registers is de Program counter. De Program counter of PC, Onthoud bij welke instructie de processor is gebleven. Dit verwijst naar een adres in de ROM. Bij iedere clockcycle wordt: (Ook weer een paar details weg gelaten.)
- Een instructie uitgelezen uit de ROM, Welke instructie wordt uitgelezen wordt bepaald door de program counter.
- De instructie uitgevoerd.
- De program counter wordt opgehoogd, zodat hij verwijst naar de volgende instructie.

Dus hoe werkt de GOTO? Nou je maakt gewoon een instructie waarbij je de program counter aanpast waar je naartoe wilt springen. Dit wordt in ASM ook wel de jump instructie genoemd. Hiermee spring je eenmalig naar een specifieke plek in de code. Een probleempje, je kan nu niet meer terug waar we vandaan kwamen. Dit is wel nodig om de functies zoals we die in C kennen te kunnen implementeren. Om dit probleem te verhelpen is de stack uitgevonden.

De stack:
De stack is een stukje geheugen dat geclaimd wordt in de RAM. De stack kan je zien als een stapel met borden. Je mag alleen borden bovenop de stack zetten of borden van de stack afhalen. Je kan nooit de middelste of onderste pakken, dan vallen alle borden kapot. De CPU zet natuurlijk geen borden op de stack. Wat hij er wel opzet zijn waarden die in de registers staan. De ASM instructies die hierbij horen worden vaak PUSH en POP genoemd. Push om iets op de stack te zetten en pop om er iets af te halen. Dus hoe kan je nu springen naar en terug springen van een functie? Simpel, Wanneer je een jump doet, zet je de program counter op de stack. Als je weer terug wilt haal je deze waarde weer van de stack en schrijft dit weer naar de program counter.

Iedere keer dat je naar een functie springt onthoud hij dus waar je vandaan bent gekomen. Als je nu 3x achter elkaar springt, dan staan er dus 3 waardes op de stack. Zoals je begrijpt is de stack niet oneindig groot. Je kunt dus maar een beperkt aantal sprongen maken. Als je het te bont maakt dan krijg je een 'stack overflow' error. Letterlijk, de stack is overstroomt.

PE2BAS
elmowww

Golden Member

Goed om te weten: goto tussen functies is (in recente standaarden) niet mogelijk: dat kan enkel binnen de functie (dus op het huidige stack niveau). Stack corruptie zou je er op deze manier dus niet van moeten krijgen. (Een goto heeft geen return).

De voornaamste reden is het spaghetti gehalte, en dat je er een aantal zaken mee kunt doen waarmee je (grote) lelijkheid maakt.

Ik kan een paar plaatsen verzinnen waar een goto netjes zou zijn; maar als je beginnend bent zou ik je juist aanraden er van af te blijven. De taal is niet meer bedoeld voor goto; en bijna alles is mooier/beter/leesbaarder op te lossen.

PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling
JoWi

Special Member

Op 22 juni 2022 10:05:52 schreef elmowww:
Goed om te weten: goto tussen functies is (in recente standaarden) niet mogelijk: dat kan enkel binnen de functie (dus op het huidige stack niveau).

Bestaan setjmp() en longjmp() niet meer ?

[TIP: Als je hier nog nooit van gehoord heb: NIET gebruiken, in 40 jaar C/C++ heb ik die functie 2X nodig gehad]

Ignorance is bliss

Ik niet. Nouja... Ik denk dat ik hem in 1992 toegepast heb. Sindsdien niet meer. Afblijven.

Ik denk niet dat ze dat soort historische shit er uit kunnen halen. Stel ik heb een programma van 30 jaar oud en wil dat opnieuw compileren, dan moet dat toch gewoon kunnen?

Ik heb in een project 25 jaar geleden een closed-source library gebruikt in een project. 22 jaar later moest dat "vernieuwd" worden, nieuwe machine, nieuw OS. Mijn code compileert nog prima. Die closed source library? Die was ondertussen opensource geworden en vrijwel alles werkte gewoon in 1x. Zo hoort het, ook als je "verouderde" technieken gebruikt.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Dat een goto niet mag komt van een publikatie van Edsgar Dijkstra genaamd "The goto statement considered harmfull". Dat is geschreven in 1968, lang voordat C werd uitgevonden. Met de talen van toen kon je van elk punt in je sourcecode naar elk ander punt springen en dat werd veelvuldig toegepast waardoor de sourcecode al snel onleesbaar werd (op de toenmalige supercomputers met 982K geheugen (CDC6600) maar ook op een PDP8 met max 6K geheugen).

En die stelling is dan weer een voorbeeld van een stelling die dan door iedereen als "universele waarheid" wordt overgenomen, terwijl er best situaties zijn waar zo een goto wel degelijk betere code oplevert. De beperkingen die C/C++ aan een goto oplegt zorgen zo-ie-zo al dat de grootste bezwaren komen te vervallen.

Maar C/C++ heeft ook ruim voldoende alternatieven zodat een goto feitelijk redelijk overbodig word. Ik zelf heb het in 40 jaar C/C++ nog nooit gebruikt.

elmowww

Golden Member

Op 22 juni 2022 11:59:46 schreef JoWi:
[...]Bestaan setjmp() en longjmp() niet meer ?

Jawel, maar dat is niet de goto waar we het over hebben.
Ik gebruik deze precies één keer per project: in de bootloader.

PA0EJE - www.eje-electronics.nl - e.jongerius[aapje]eje-electronics.nl - EJE Electronics - Elektronica/firmware ontwikkeling

Sowieso zijn setjmp() en longjmp() functies in C, dus iedereen die ze wil gebruiken kan ze implementeren indien nodig.

C kent ook functie-pointers (oftewel, adressen van instructies).
Daarmee kun je goto, computed goto, functie-tabellen en interupt vector tabellen maken.

Maar behalve voor callbacks en bootloader/interrupt werk gebruik ik ze nooit.

Op 21 juni 2022 20:28:55 schreef SparkyGSX:
[...] Als je dat perse wilt mag die break ook op dezelfde regel hoor, maar je hebt het niet helemaal begrepen, want in jouw voorbeeld wordt er volgens mij niets geprint bij een B.

Misschien was er een goede reden dat ik jou nooit software heb laten schrijven ;)

Ik zie het nu, je wil B laten doorvloeien naar C, nog eenvoudiger:

code:


case Grade of
   'A': Writeln('Excellent!');
   'B','C': Writeln('Well done');
   'D': Writeln('You passed');
   'F': Writeln('Better try again!');
   else Writeln('Invalid grade');
end;

Kan ook met 'G'..'Z' etc

Grappig weetje, de E is uit het grading system gehaald omdat leerlingen hun ouders hadden wijsgemaakt dat de E voor excellent staat. Dus zijn ze over gegaan op F van Failed.

PE2BAS