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

blackdog

Golden Member

Hi,
Ik krijg met deze vraag waarschijnlijk een aantal bliksemschichten mijn kant op gestuurd van jullie, maar ik stel deze vraag toch! :+

Waarom zou ik Goto/Return niet moeten gebruiken in de software die ik in elkaar frut met Arduino's Microcontrolers?
Ik zal nooit een High End Developer worden, maar voor mijn Dyslectische brein kan het helpen stukjes code voor mij overzichtelijk te houden.
Vooral als ik in het begin zit bij het opzetten en ja ik wil het in principe goed doen, maar dat kost ook erg veel tijd voor mij door het taalprobleem.

Als het dan werkt kan ik het altijd nog aanpassen naar enigsins goede code binnen mijn capaciteiten,
tijdproblemen in de loop zullen waarschijnlijk geen probleem worden, ik gebruik liever snelle Teensy's dan goedkopere typen.
De exta kosten van de Teensy neem ik graag voor lief.

Wat is het echte probleem als ik soms dit nodig heb voor het overzicht en is de manier in de Arduino IDE ongeveer gelijk aan hoe ik dit vroeger deed in Batch scripts?

Mijn brein werkt anders dan die van jullie en het is handig als dit bij de uitleg die jullie misschien gaan geven, om daar rekening mee te houden.
In ieder geval dank vast voor de input!

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.
Totale beginner

Golden Member

Hallo Blackdog,

Met return is in mijn ogen zeker niets mis. Het is een veelgebruikt basis statement en helemaal niets mis mee.

goto is een statement die in onbruik is geraakt omdat het makkelijk tot spaghetticode lijkt. Persoonlijk gebruik ik goto enkel als een soort veredelde 'catch' gebruikt. Bv:

pic asm code:


void my_function(void)
{
  char *buf = malloc(8);
  
  if(xx) {
    goto cleanup
  }

  for() {
    if(yy) {
      goto cleanup
    }
  }

cleanup:
  free(buf)
}
Sine

Moderator

https://imgs.xkcd.com/comics/goto.png

Als niet coder:

Er zijn meestal genoeg alternatieven om spaghetti code te voorkomen.

Zeker omhoog springen in een programma is een flinke no-no

En inderdaad, do-while of gosub return.

Goto is net alcohol. Een beetje, af en toe is niet erg en kan zelfs prettig zijn.

Maar overdaad schaad.

Meer to-the-point, wat totale beginnner in feite ook al schrijft, goto is heel geschikt voor fout-afhandeling.

Je code blijft leesbaarder als de opbouw overeenkomt met de normale gang van zaken. Fouten, vooral onwaarschijnlijke, wil je echter wel afvangen. En meestal onderbreek je de flow dan en is het (in ieder geval op het niveau van je huidige functie) gewoon einde verhaal.

Dan is een goto veel netter dan eindeloze geneste if/else blokken.

try/catch exception handling is ook goed, en heeft als voordeel dat het wellicht duidelijker is dan goto. Maar de resulterende code is vrijwel gelijk qua vorm, en volgens mij zijn er ook taal-puristen die try/catch gewoon "syntactic suger" voor goto noemen.

Plus dat niet alle C-compilers, en zeker niet alle standaard libraries exceptions ondersteunen.

mel

Golden Member

Ik ben gewend om in assembler te werken, dus elke instructie apart ingeven. Als je precies weet hoe je het programma wilt hebben, is dat wel te doen. Van C weet ik echt niks van.

u=ir betekent niet :U bent ingenieur..

Het probleem van goto is dat je het overzicht makkelijk kwijt raakt. Als je meerdere kleinere functies maakt dan heb je dit probleem niet.

Stel je voor je hebt 20 regels code om een motortje te laten draaien. Dan kan je telkens als je die motor wilt laten draaien die 20 regels neerzetten. Makkelijker is om een losse functie te maken en die aan te roepen. Bijvoorbeeld StartMotor(); Je kunt die dan overal in de code gebruiken en je mag ervan uitgaan dat die functie doet wat hij moet doen. Als er iets moet veranderen, bijvoorbeeld een andere motor driver, dan hoef je alleen de code in die functie aan te passen.

Wat betreft goto, stel je maakt een label die noem je STARTMOTOR. Als je nu een goto doet, dan weet je niet wat er gebeurt nadat je die sprong hebt gemaakt. Je komt niet altijd terug waar je de goto hebt aangeroepen. Vervelend want dan raak je het overzicht snel kwijt.

Ik weet niet waar je hebt gelezen dat een return niet zou mogen. Functies in C werken niet zonder een return. (Misschien bij een void maar die gebruikt stiekem ook een return.) Wellicht bedoelen ze hier dat je beter 1 return kan plaatsen op het einde. Daar is idd wat voor te zeggen. Persoonlijk ben ik voorstander om functies klein en overzichtelijk te houden en voor een specifiek doel te maken. In functies gebruik ik vaak returns als 'sanity check' bijvoorbeeld:

c code:


void StartMotor(int rpm, float maxTorque)
{
	if(rpm > 10000)
		return; 		//Motor can't run faster than 10000rmp
	
	if(maxTorque > 5.0f)
		return;			//Motor can't handle more than 5nm
	
	
	/*
	Here comes the code to actually start the motor
	*/
	
	return;
}

Ik heb nog nooit goto's nodig gehad. Zelfs niet in foutafhandeling. Als ik goed begrijp wat jullie bedoelen. Zelf zou ik eerder voor een statemachine opzet kiezen met een switch.

Wat betreft ASM, tja, ik zie niet echt een reden om dat nog te willen schrijven. Op een paar heel specifieke toepassingen na.

PE2BAS
bprosman

Golden Member

Als je bijvoorbeeld een Switch statement gebruikt en ipv printf roep je een eigen functie aan dan is dat eigenlijk een verkapte "Goto".
Eigenlijk doe je hier ook een "Goto Printf".
Je springt naar de functie toe en keert terug op de "Return" van de functie :

c code:

#include <stdio.h>
 
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 );
De jongere generatie loopt veel te vaak zijn PIC achterna.

@bprosman: inderdaad, een case is een verkapte goto, maar die is wel veel leesbaarder, omdat de cases binnen de scope van de switch staan, en je dus nooit terug springt (omhoog in de code), of ergens anders waarvoor je het label moet gaan zoeken. Je maakt maximaal 2 jumps, de eerste van het begin van de switch naar de juiste case, en vanaf daar (als het niet de default of een on-afgesloten case was) naar het eind van de switch. Het eindpunt is altijd hetzelfde, en de jump is altijd vooruit, binnen een beperkte scope.

Ik ben het helemaal met hardbass eens; in 25 jaar C programmeren heb ik exact 0 keer een goto gebruikt of nodig gehad.

Ook ik doe vaak aan het begin van een functie wat sanity checks met een return. Dat heeft als voordeel dat het direct duidelijk is waar je heen gaat (terug naar waar de functie werd aangeroepen), en in de rest van de functie weet je dat de sanity checks goed waren, anders was je nooit verder gekomen in die functie.

Strikt genomen is zo'n return eigenlijk ook een jump naar de gegenereerde code aan het eind van de functie die de stack weer opruimt en zo. Daarnaast heb je nog break en continue, waarmee je uit een loop kunt springen, of juist het uitvoeren van de huidige iteratie onderbreekt, en verder gaat bij de volgende iteratie. Ook die probeer ik altijd te vermijden, afgezien van de break in een switch case, want daar zijn ze gewoon verplicht (wat ik overigens een vreselijk lelijke constructie vind).

In vrijwel alle gevallen waar je een goto zou gebruiken, kan het ook zonder, wat de leesbaarheid van de code doorgaans veel beter maakt, en mogelijke fuckups voorkomt.

Voorbeeld:

code:


if( a > 2 ) goto TEGROOT;

function( a ); 

TEGROOT:

kun je beter schrijven als

code:


if( a <= 2 )
  function( a );

Het enige "redelijke" argument dat ik ook vóór een goto heb gehoord, is als je aan het eind van de functie nog dingen moet opruimen, ongeacht of je de taak van de functie hebt kunnen volbrengen of niet, maar ook daar zijn altijd betere oplossingen voor.

Kortom: als je een goto nodig hebt, doe je gewoon fundamenteel iets fout. Soms is het alternatief om een vlaggetje te zetten en die verderop te testen.

Voorbeeld:

code:


char SanityCheck = 1;

if( a > 2 )
  SanityCheck = 0;

if( weekday == Sunday )
  SanityCheck = 0;

if( SanityCheck )
  function( a );

cleanup();

Voor het geval iemand het niet met me eens is: geef eens een voorbeeld waar "goto" redelijkerwijs de beste oplossing is, ik ben oprecht benieuwd.

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

De ARM architectuur, waarschijnlijk ook andere, hebben instructies die mooi aansluiten bij functie calls. De push en pop icm stack, specifieke afspraken over de gebruikte registers voor de return waardes en de argumenten. Compilers kunnen zo ook mooi uitrekenen wat de grootst benodigde stacksize is. (Mits je je aan een aantal regels houd.) Dit kan best wat voordelen opleveren in situaties waar stabiliteit nodig is. Maar goed, dit gaat wel een stapje te ver voor de gemiddelde hobbyist. Als professional is het wel goed dat je weet hoe deze zaken werken. Tenminste, op embedded spul, zit je met grote kubernetes clusters boeien dat soort dingen niet meer zo.

Wat betreft de continue en break, deze gebruik ik praktisch alleen in verband met optimalisaties. Dus niet heel de lus aflopen als je het antwoord al hebt.

Switches vind ik zelf ook niet heel mooi, zeker als ze veel code bevatten of je er 2 in elkaar stopt. Brrr.

Ik probeer mijn functies beperkt te houden in grootte, zo is het altijd overzichtelijk wat er in een functie gebeurt. Opsplitsen van verantwoordelijkheden in meerdere kleinere functies maakt je leven echt leuker. :)

Samengevat: Abstractie.

Oh, een leuk voorbeeldje van een statemachine. Dit is een weegschaaltje wat de meetresultaten doorstuurt naar een database. Er zijn best wat dingen mooier te maken maar de statemachine opzet is wel grappig. Het idee is dat iedere state uit 3 stukken bestaat.

1. De 'OnEntry' dit wordt 1x uitgevoerd nadat de state is veranderd.
2. De 'continuous' dit wordt herhaaldelijk uitgevoerd. Bijvoorbeeld een meting om te kijken of iemand op de weegschaal staat.
3. De 'transitions' hier wordt bepaald of er naar een andere state moet worden gesprongen.

https://github.com/vanBassum/WifiScale/blob/master/ESP32/main/main.cpp
(Nu met gratis wifi :+ )

Dit idee van deze statemachines gebruik ik op veel plekken. Wat ook mooi is, je kan de state switches loggen. Op die manier zie je erg goed wat er in je programma gebeurt. Ik heb een los tooltje waarmee ik de states kan weergeven over tijd. (Een soort logic analyser beeld) Dit geeft enorm veel inzicht wanneer je states veranderen en hoelang je in een bepaalde state zit. Erg praktisch als je meerdere state machines krijgt en er gaat 'iets' niet zoals verwacht.

PE2BAS
blackdog

Golden Member

Hi,

Ook nu is het weer het zelfde...

Het gaat er om hoe b.v. Goto MIJ kan helpen en niet hoe jullie het al jaren doen en dat het niet zinvol is wat ik wil.
Ik zie graag Jip en Janneke voorbeelden hoe ik het beter kan aanpakken, dat is de manier hoe ik met alles start wat ik moet leren.
Nogmaals ik ben geen Developer en zal dat ook nooit worden, verder sta ik nog aan het begin van het programmeren.

Als een willekeurig iemand hier stelt, misschien is een state machine handig, dan zal ik dan eerst moeten gaan leren wat een state machine is!
deKees heeft jaren geleden eens iets voor mij opgelost via een state machine, en dat is alles wat ik nog weet er van.

Dus graag er rekening mee houden met mijn taaltoestand.
Ik ken mijn beperkingen en omdat ik bewust ben van het taalprobleem, probeer ik daar zo goed mogelijk mee om te gaan.

Dus simpele voorbeelden, (wat voor jullie simpel is, hoeft voor mij niet zo te zijn) anders kost het nog veel te veel tijd om allerlei zaken te gaan uitzoeken.
En nee, ik ben absoluut niet lui en leer heel graag, dat moet zo langzamerhand nu wel duidelijk zijn. :-)

Bij code die ik regelmatig zie staat er aan het einde onder de loop b.v. dit:

void Action-01()

void Action-02()

void Action-03()

Moet ik dat zien als een "goto" en als Action-01 is afgewerkt wordt er dan weer terug gesprongen naar het punt of beter de volgende stap in de loop, waar Action-01 werd aangeroepen?

Als alleen Action-01 in de loop wordt aangeroepen wordt dan Action-02 en Action-03 genegeert, ik denk het wel, want het zit buiten de main loop.

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.

Dat is niet te zeggen zonder de rest van de code. Als je 3 function calls achter elkaar zet, worden ze in die volgorde, achter elkaar, uitgevoerd.

code:


for( a = 0; a < 10; a++ )
{
  action_1();
  action_2();
  action_3();
}

Hier wordt dus action_1 uitgevoerd, dan action_2, dan action_3, dan weer action_1, action_2, etc., voor in totaal 10 keer.

Let op dat alle function calls binnen de "scope" van de loop staat, dat wil zeggen, tussen { en }, en daarom worden ze allemaal elke keer uitgevoerd.

Als je dit schrijft:

code:


for( a = 0; a < 10; a++ )
  action_1();

action_2();
action_3();

dus zonder { en }, waarbij ik zelf altijd een extra lege regel gebruik na de function call action_1(), wordt action_1 10x achter elkaar uitgevoerd, en daarna action_2 en action_3 allebei maar 1x. Als je in het eerste voorbeeld alleen de haakjes weghaalt, maar het inspringen niet veranderd, en geen lege regel toevoegt, is dat niet direct duidelijk. Die extra regel maakt er duidelijk een blok van, waar action_2 en action_3 dus niet bij horen.

Op 21 juni 2022 15:07:59 schreef blackdog:
Het gaat er om hoe b.v. Goto MIJ kan helpen en niet hoe jullie het al jaren doen en dat het niet zinvol is wat ik wil.

Nu ga ik deze even naar je terug kaatsen:

De tips die ik geef hier op CO in de stukjes die ik schrijf mag iedereen in de wind slaan.
Alles zelf door mij uitgevonden, natuurlijk niet, zeer veel lezen over de techniek waar ik interessen in heb, ik sta op de schouders van de grijze baarden, ik zelf ben niet zo groot.
Jullie bepalen zelf of je wel of niet wil leren van wat ik hier op CO type.

[Bericht gewijzigd door SparkyGSX op dinsdag 21 juni 2022 15:21:11 (23%)

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

Op 21 juni 2022 15:07:59 schreef blackdog:
Moet ik dat zien als een "goto" en als Action-01 is afgewerkt wordt er dan weer terug gesprongen naar het punt of beter de volgende stap in de loop, waar Action-01 werd aangeroepen?

Nee, een functie-call (in C is dat alles dat eindigt met ronde haakjes()) is geen goto.

In C kun je nooit terug van een goto1. Van een functie kom je altijd terug2.

(1) Behalve dan door de triviale manier door terug te springen met een tweede goto. Maar dat is dus spagetti.

(2) Behalve dat als de functie de exit() functie aanroept waarmee het OS gevraagd wordt het programma te be-eindigen. Wat je in een embedded systeem eigenlijk nooit doet.

Op 21 juni 2022 15:36:28 schreef rew:
[...]Nou, jou voorbeeld dus.

Jij hebt maar 1 "if (sanitycheck)", maar dat worden er snel veel.

code:


if (...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;

Dan kan er beter steeds "goto cleanup" staan.

Op 21 juni 2022 14:19:20 schreef SparkyGSX:
Voor het geval iemand het niet met me eens is: geef eens een voorbeeld waar "goto" redelijkerwijs de beste oplossing is, ik ben oprecht benieuwd.

Nou, jou voorbeeld dus.

Jij hebt maar 1 "if (sanitycheck)", maar dat worden er snel veel.

code:


if (...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;
if (sanitycheck && ...) sanitycheck=0;

Dan kan er beter steeds "goto cleanup" staan. (even voor de goede orde: die ... zitten dan ook functie aanroepen tussen zodat je niet zomaar 1 "if (sanitycheck) {.. }" kan doen. Of in de "then" clausule van de if gebeurt nog eea wat conditioneel weer een "cleanup... exit" moet triggeren. )

[Bericht gewijzigd door rew op dinsdag 21 juni 2022 16:46:51 (37%)

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

Op 21 juni 2022 15:07:59 schreef blackdog:
Hi,

Ook nu is het weer het zelfde...

Het gaat er om hoe b.v. Goto MIJ kan helpen en niet hoe jullie het al jaren doen en dat het niet zinvol is wat ik wil.
Ik zie graag Jip en Janneke voorbeelden hoe ik het beter kan aanpakken, dat is de manier hoe ik met alles start wat ik moet leren.
Nogmaals ik ben geen Developer en zal dat ook nooit worden, verder sta ik nog aan het begin van het programmeren.

Als een willekeurig iemand hier stelt, misschien is een state machine handig, dan zal ik dan eerst moeten gaan leren wat een state machine is!
deKees heeft jaren geleden eens iets voor mij opgelost via een state machine, en dat is alles wat ik nog weet er van.

Dus graag er rekening mee houden met mijn taaltoestand.
Ik ken mijn beperkingen en omdat ik bewust ben van het taalprobleem, probeer ik daar zo goed mogelijk mee om te gaan.

Dus simpele voorbeelden, (wat voor jullie simpel is, hoeft voor mij niet zo te zijn) anders kost het nog veel te veel tijd om allerlei zaken te gaan uitzoeken.
En nee, ik ben absoluut niet lui en leer heel graag, dat moet zo langzamerhand nu wel duidelijk zijn. :-)

Bij code die ik regelmatig zie staat er aan het einde onder de loop b.v. dit:

void Action-01()

void Action-02()

void Action-03()

Moet ik dat zien als een "goto" en als Action-01 is afgewerkt wordt er dan weer terug gesprongen naar het punt of beter de volgende stap in de loop, waar Action-01 werd aangeroepen?

Als alleen Action-01 in de loop wordt aangeroepen wordt dan Action-02 en Action-03 genegeert, ik denk het wel, want het zit buiten de main loop.

Groet,
Bram

Ahja, ik liet me een beetje meeslepen door de enthousiasme voor techniek. :)

Het is voor mij ook lastig te bepalen waar je staat qua programmeer kennis. Misschien is het makkelijker om het andersom te doen, als jij nou een stukje code laat zien met goto's kunnen wij wellicht een voorzetje doen naar een betere structuur?

Heb je de mogelijkheid om te debuggen?
Dat heeft mij vroeger erg veel geholpen om te zien wat er gebeurt. Je kan daarmee namelijk stap voor stap door de code lopen. Zo zie je precies wat de processor doet.
(Ik kan even voor je zoeken naar een makkelijke manier om te debuggen.)

-------
Concreet antwoord op je vraag uit je laatste post. Beschouw de volgende code:

c code:


void main()
{
	Action1();
	Action2();
}

void Action1()
{
}

void Action2()
{
}

Wat gebeurt hier.
1. De processor start op en begint altijd bij main.
2. Hier staat een functie call, dat wil zeggen hij gaat nu eerst naar action1 en die code uitvoeren.
3. Als action1 klaar is, dan sprint hij terug naar de main, waar hij was gebleven.
4. Nu komt de volgende functie call, namelijk action2.
5. Als action2 klaar is, dan sprint hij terug naar de main, waar hij was gebleven.
6. De main bevat niet meer code, dus hij is klaar.

------------
Maar, eerlijk gezegd denk ik dat je meer hebt aan een cursus C of arduino. Die gasten kunnen dat veel beter uitleggen dan ik dat kan. ;)

PE2BAS
blackdog

Golden Member

Hi SparkyGSX

En wat wil je nu zeggen, dat je het weer niet gegrokt hebt? ;)

OK nogmaals de loop is aan zijn eindje => } <= Klaar
Daaronder staan nog drie stukjes uit te voeren code (kan dit trouwens op die manier?)

void Action-01()
.
.
.

Klaar-01 (wordt er nu terug gesprongen naar de volgede uit te voeren stap, of wordt void Action-02() nu uitgevoerd, lijkt mij niet logis, maar wie ben ik. :-)

void Action-02()
.
.
.
Klaar-02

void Action-03()
.
.
.
Klaar-03

Hieronder een stukje code uit een Library
Wat mij betreft zijn dat dus net zoiets als in Batchfiles "GOTO/Return" en hier hebben ze de namen "void Action()" en "void ButtonCheck()"

Of zie ik het nog steeds verkeerd?

Groet,
Bram

c code:


/*
AnalogButton_Combos
Version 0.1
Created By: Michael Pilcher
February 24, 2010

*/
int j = 1; // integer used in scanning the array designating column number
//2-dimensional array for asigning the buttons and there high and low values
int Button[4][3] = {{1, 837, 838}, // button 1
                    {2, 737, 738}, // button 2
                    {3, 610, 611}, // button 3
                    {4, 318, 319}}; // button 4
                  
int analogpin = 5; // analog pin to read the buttons
int label = 0;  // for reporting the button label
int counter = 0; // how many times we have seen new value
long time = 0;  // the last time the output pin was sampled
int debounce_count = 50; // number of millis/samples to consider before declaring a debounced input
int current_state = 0;  // the debounced input value
int ButtonVal;

void setup()
{
 Serial.begin(9600);

}

void loop()
{
  // If we have gone on to the next millisecond
 if (millis() != time)
 {
   // check analog pin for the button value and save it to ButtonVal
   ButtonVal = analogRead(analogpin);
   if(ButtonVal == current_state && counter >0)
   {
     counter--;
   }
   if(ButtonVal != current_state)
   {
     counter++;
   }
   // If ButtonVal has shown the same value for long enough let's switch it
   if (counter >= debounce_count)
   {
     counter = 0;
     current_state = ButtonVal;
     //Checks which button or button combo has been pressed
     if (ButtonVal > 0)
     {
       ButtonCheck();
     }
   }
   time = millis();
 }
}

void ButtonCheck()
{
 // loop for scanning the button array.
 for(int i = 0; i <= 4; i++)
 {
   // checks the ButtonVal against the high and low vales in the array
   if(ButtonVal >= Button[i][j] && ButtonVal <= Button[i][j+1])
   {
     // stores the button number to a variable
     label = Button[i][0];
     Action();      
   }
 }
}

void Action()
{
 if(label == 1)
 {
   Serial.println("Up Button");
 }
 if(label == 2)
 {
   Serial.println("Down Button");
 }
 if(label == 3)
 {
   Serial.println("Left Button");
 }
 if(label == 4)
 {
   Serial.println("Right Button");
 }
 
   Serial.println("Action Buttons #1 and #2");
  
     
 //Serial.println("Button =:");
 //Serial.println(label);
 //delay(200);
  
}
You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Een functie keert terug naar de plek waar hij is aangeroepen. Dat kan dus halvewegen een andere functie zijn. Een goto doet dat niet. Die gaat altijd naar een label.

Hmm, ik weet niet of dit nu wel zo handig is. Doordat iedereen je wilt helpen wordt het niet duidelijker denk ik. Ik wil toch nog een poging wagen.

Ik heb een stukje code gemaakt in C met functies en met goto wat exact hetzelfde werkt.

c code:


void main()
{
	Action1();
	Action2();
}

void Action1()
{
	printf("Hallo wereld");
}

void Action2()
{
	printf("Hello world");
}

c code:


main:
goto action1;
return_action1:
goto action2;
return_action2:
(END OF PROGRAM)

action1:
printf("Hallo wereld");
goto return_action1;


action2:
printf("Hello world");
goto return_action2;

[Bericht gewijzigd door hardbass op dinsdag 21 juni 2022 15:58:51 (66%)

PE2BAS
blackdog

Golden Member

Hi hardbass,

Het gaat mij er om dat ik kan springen naar een apart stukje code zoals aangegeven in de echte code.
Het hoeft niet GOTO te heten :-)

Dus ik kan b.v. als void Action-01() wordt uitgevoerd als nodig spingen naar void Action-03() daarin void Action-02() laten uitvoeren om uiteindelijk void Action-01() verder af te werken en weer terug te keren waar ik vandaan kom toen void Action-01() werd aangeroepen, begrijp ik dat goed?

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 15:43:21 schreef blackdog:
Hieronder een stukje code uit een Library
Wat mij betreft zijn dat dus net zoiets als in Batchfiles "GOTO/Return" en hier hebben ze de namen "void Action()" en "void ButtonCheck()"

Mijn MS-DOS batch is een beetje roestig (als in: de titanic is er beter aan toe), maar was .bat niet de plek waar je een subroutine/functie aanriep met goto?

Voor de rest van de wereld zijn goto en functies geheel verschillende dingen.

Op 21 juni 2022 15:59:11 schreef blackdog:
Hi hardbass,

Het gaat mij er om dat ik kan springen naar een apart stukje code zoals aangegeven in de echte code.
Het hoeft niet GOTO te heten :-)

Dus ik kan b.v. als void Action-01() wordt uitgevoerd als nodig spingen naar void Action-03() daarin void Action-02() laten uitvoeren om uiteindelijk void Action-01() verder af te werken en weer terug te keren waar ik vandaan kom toen void Action-01() werd aangeroepen, begrijp ik dat goed?

Groet,
Bram

Klopt, dan krijg je dus dit:

c code:


void Action1()
{
	//Code 
	//Nog meer code
	Action3();
	//Nog wat code
}


void Action2()
{
	//Code 
}


void Action3()
{
	//Code 
	//Nog meer code
	Action2();
	//Nog wat code
}
PE2BAS
blackdog

Golden Member

Hi blurp

Het gaat er uiteindelijk om dat ik wat structuur kan aanbrengen in het programmeren, zodat het voor mij makkelijker wordt.
Ik nam GOTO/RETURN dat ik in Batchfiles gebruikte als voorbeeld en bij mij is dat natuurlijk ook zo roestig als wat. :)

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.
blackdog

Golden Member

Hi,

Kijk, nu wordt het voor mij in ieder geval weer een stukje duidelijker, mijn dank hiervoor Heren. :+
Hi hardbass, schrijf je zelf niet te snel af, je bent een van de gene die mij het vaakst begrijpt en het voor mij goed duidelijk maakt, ook deze keer weer!

Groet,
Bram

[Bericht gewijzigd door blackdog op dinsdag 21 juni 2022 16:16:46 (39%)

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

Voor C en C++ geldt in principe dat eerst alle variabelen worden geïnitialiseerd, en vervolgens wordt alleen de main() funktie uitgevoerd.

Alle andere code wordt niet vanzelf uitgevoerd. Maar doorgaans worden extra funkties toegevoegd omdat ze vanuit de main worden aangeroepen.

Ook in de Arduino wordt alleen de main() funktie aangeroepen, maar daar zit die main() functie verstopt in de IDE en die krijg je niet te zien. De main() voor arduino doet het volgende:

code:


int main()
{  setup();
   for( ;; )
   {  loop();
   }
}  

Dus dan wordt de setup() éénmalig uitgevoerd bij opstarten en vervolgens wordt loop() steeds herhaald.
Dan kun je zelf bepalen wat er in setup() en en loop() gebeurt omdat je die functies zelf moet aanleveren.

Het kwartje is gevallen, top!

Vooral blijven proberen. Mijn code van vroeger ziet er ook niet uit, en nu nog wel eens niet. 8)7 Zolang je geen medische apparatuur maakt kan je je een bug hier en daar best veroorloven.

PE2BAS

Op 21 juni 2022 15:49:29 schreef hardbass:
Ik heb een stukje code gemaakt in C met functies en met goto wat exact hetzelfde werkt.

Nou.... Vandaag nog wel. Maar jou "bat"-code is niet "herbruikbaar": Als je nog een keer "action1 ()" wil uitvoeren, moet je een nieuwe copie maken, want de return gaat anders naar de eerste terug.

Dus in geen geval wil je dat soort code schrijven. Het werkt dupliceren in de hand (je code wordt snel veel groter dan jij aankan) en wordt snel spagetti.

In C kan je een functie maken:

code:


 
print_getal_met_label (char *label, int getal)
{
  printf ("getal %s=%d.\n", label, getal);
}

en dan meerdere malen gebruiken:

code:


if (..... ) print_getal_met_label ("stroom(mA)", stroom);

....
print_getal_met_label ("spanning(V)", spanning);

(bij arduino.... geloof ik niet dat je direct "printf" hebt, dus daar moet je iets denken als clear LCD, teken het label, teken het getal).

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

@blackdog,
Voor wie schrijf je die code?
Is het voor jezelf, dan zou ik me over die goto-statement geen zorgen maken.
Veel belangrijker is goed commentaar in je code opnemen.
Nu de code net geschreven is snap je precies wat er gebeurt, maar een half jaar of een jaar later als je onderhoud of een kleine wijziging aan die code wilt doen, dan snap je die code niet of na heel veel moeite als er geen goed commentaar bij geschreven is.
Nu wordt er gesteld dat je spaghetti-code krijgt als je goto-statements gebruikt. Who cares? Een beginnend programmeur schrijft kleine programma's en als dat spaghetti-code is is dat niet erg. Één draad spaghetti ontrafelen is eenvoudig, een bord spaghetti ontrafelen is iets moeilijker en een pan spaghetti ontrafelen is lastig.