Forum: PC-Programmierung Warum goto vermeiden


von BloedeFrage (Gast)


Lesenswert?

Hallo, warum soll ich goto nicht nutzen?
Danke

von Yalu X. (yalu) (Moderator)


Lesenswert?

BloedeFrage schrieb:
> Hallo, warum soll ich goto nicht nutzen?

Ich würde sagen, zu diesem Thema findest du bereits jedem Menge
Informationen und Diskussionen im Netz. Hast du schon alle gelesen? Wo
sind noch offene Detailfragen?

von NoGoTo (Gast)


Lesenswert?

1. weils auch ohne geht

2. weils ohne besser geht

3. weils mit schlechter geht

4. weils keiner braucht

5. wers trotzdem benutzt sollte sich über seine Herangehensweise 
Gedanken machen, seine Fehler selber suchen und eventuell mal über eine 
andere Sprache nachdenken, die einen von vornherein durch das schlichte
"goto-nicht-vorhanden-sein"
vor derartigen Irrwegen bewahrt

von Zwergenball (Gast)


Lesenswert?

BloedeFrage schrieb:
> Hallo, warum soll ich goto nicht nutzen?

Wer fordert das von dir?

> Danke

Bitte.

von BloedeFrage (Gast)


Lesenswert?

Sämtliche Leute die mir bisher programmieren beigebracht haben

von Zwergenball (Gast)


Lesenswert?

BloedeFrage schrieb:
> Sämtliche Leute die mir bisher programmieren beigebracht haben

Wie viele haben dir das programmieren beigebracht? Welche 
Programmiersprachen hast du dabei erlernt? Haben diese Leute die 
Forderung - goto nicht zu verwenden - begründet? Wie wurde die Forderung 
begründet? Wie alt bist du? Welchen Schulabschluss hast du? Hast du 
einen Hochschulabschluss? Wenn ja, welchen Anschluss hast?

von Klaus Kaiser (Gast)


Lesenswert?

Dieses Dogma hält sich deshalb so gut, weil es deutlich einfacher ist, 
zu verlagen, es nicht zu benutzen, als zu verstehen, wie man es richtig 
benutzt.

Gernationen von Programmierern haben deshalb nicht einmal versucht zu 
verstehen, wie man es richtig benutzt.

Es lohnt sich, die diversen Abhandlungen azuschauen und auch mal einen 
Blick in den Linux-Kernel zu werfen anstatt goto unbegründet zu 
verteufeln.

In der Tat gibt es wenige gute Anwendungsszenarien für goto, aber es 
gibt sie!

von Karl H. (kbuchegg)


Lesenswert?

BloedeFrage schrieb:
> Hallo, warum soll ich goto nicht nutzen?

Weil die Erfahrung lehrt, dass so etwas bei jemandem der es nicht kann, 
ganz schnell zu unwartbarem Spaghetticode führt.

Es gibt Einsatzfälle für goto. Aber das sind ganz spezielle Fälle. 
Einfach mit goto wie wild drauf los programmieren, führt fast immer ins 
Chaos. Speziell bei Anfängern. Ein Profi hingegen braucht so etwas nicht 
zu fragen. Der weiß, wann ein goto tatsächlich die einfachste und beste 
Lösung ist und wann nicht.

von Rolf Magnus (Gast)


Lesenswert?

BloedeFrage schrieb:
> Sämtliche Leute die mir bisher programmieren beigebracht haben

Als Anfänger tut man gut dran, es zu vermeiden, da es eine relativ hohe 
Gefahr birgt, damit schlechten Code zu schreiben.
Es gibt aber Fälle, in denen es durchaus sinnvoll ist. Wer das generell 
meidet wie der Teufel das Weihwasser, der hat's aber nicht wirklich 
verstanden.

von Rolf Magnus (Gast)


Lesenswert?

Klaus Kaiser schrieb:
> Dieses Dogma hält sich deshalb so gut, weil es deutlich einfacher ist,
> zu verlagen, es nicht zu benutzen, als zu verstehen, wie man es richtig
> benutzt.

Allerdings. Wenn man sich Richtlinien wie MISRA anschaut, findet man 
noch jede Menge weitere Regeln, die genau in die selbe Kerbe schlagen.

> Gernationen von Programmierern haben deshalb nicht einmal versucht zu
> verstehen, wie man es richtig benutzt.

Das sehe ich auch immer wieder. Die schlagen die Hände schon über dem 
Kopf zusammen, wenn man goto nur erwähnt, aber wenn man genauer 
nachhakt, merkt man, daß sie eigentlich gar nicht wissen, warum. Es 
werden halt nur die Sprüche derer, von denen man die Sprache gelernt 
hat, nachgeplappert, ohne sie zu verstehen.

von BloedeFrage (Gast)


Lesenswert?

GENAU aus dem Grund habe ich die Frage gestellt. Und habe jetzt, 
zumindest ein paar, brauchbare Einschätzungen erhalten. Es geht also vor 
allem um die Lesbarkeit, welche durch (schwer nachzuvollziehende) 
Sprünge leidet. Richtig?

von Klaus Kaiser (Gast)


Lesenswert?

Falsch.

Google mal nach "goto statement considered harmfull".

von Gozo (Gast)


Lesenswert?

>In der Tat gibt es wenige gute Anwendungsszenarien für goto, aber es
>gibt sie!
Was wäre denn ein gutes Beispiel? Das Abbrechen einer verschachtelten 
Schleife oder Fehlerbehandlung?

von Klaus Kaiser (Gast)


Lesenswert?


von Jürgen S. (jurs)


Lesenswert?

BloedeFrage schrieb:
> GENAU aus dem Grund habe ich die Frage gestellt. Und habe jetzt,
> zumindest ein paar, brauchbare Einschätzungen erhalten. Es geht also vor
> allem um die Lesbarkeit, welche durch (schwer nachzuvollziehende)
> Sprünge leidet. Richtig?

Mal eine kleine Beispielfunktion (Arduino), die 2 zurückliefert, wenn 
man 1 als Parameter übergibt und die 1 zurückliefert, wenn man 2 als 
Parameter übergibt und ansonsten eine Fehlermeldung auf Serial ausgibt.
1
int tausche_1_2(int i)
2
// liefert 2 bei Eingabe 1
3
// liefert 1 bei Eingabe 2
4
// liefert sonst i und eine Serial-Fehlermeldung bei allen anderen i
5
{
6
  if (i == 1) goto skip_1; 
7
  if (i == 2) goto skip_2;
8
  goto error;
9
  skip_1:
10
  i = 2; 
11
  goto done;
12
  skip_2: 
13
  i = 1; 
14
  goto done;
15
  error:
16
  Serial.print("Falscher Eingabewert: ");
17
  Serial.println(i);  
18
  done: ;
19
  return(i);
20
}

Schöner geht es doch nun wirklich nicht, oder?
;-)

Bei den uralten BASIC Dialekten ist das mit dem GOTO übrigens dadurch 
gekommen, dass pro Programmzeile (das waren Interpretersprachen mit 
numerierten Zeilen) nach einer if-Abfrage nur ein einzelner Befehl 
ausgeführt werden konnte. Für if-Zweige gab es keine Codeblöcke. Daher 
war es dann eben oft so, dass als einziger erlaubter Befehl nach einer 
positiven if-Bedingung ein GOTO-Sprung gemacht wurde.

Seit alle Programmiersprachen Codeblöcke nach einer if-Bedingung 
erlauben (selbst BASIC kann das seit Jahrzehnten) ist GOTO relativ 
überflüssig.

Nützlich ist "goto" ist heute noch ggf. beim Herausspringen aus mehrfach 
verschachtelten for-Schleifen, wenn man aus einer der inneren 
for-Schleifen direkt herausspringen möchte.

von Paul B. (paul_baumann)


Lesenswert?

Jürgen schrub:
>Nützlich ist "goto" ist heute noch ggf. beim Herausspringen aus mehrfach
>verschachtelten for-Schleifen, wenn man aus einer der inneren
>for-Schleifen direkt herausspringen möchte.


Das ist aber keine gute Idee, da mit GOTO herauszuspringen, weil das
jede Menge "Trümmer" hinterläßt.

Bei Bascom gibt es für solche Aktionen diese Befehle:
EXIT FOR

EXIT DO

EXIT WHILE

EXIT SUB

EXIT FUNCTION
*******************************************************************
Exit Paul

von 132 (Gast)


Lesenswert?

NoGoTo schrieb:
> 3. weils mit schlechter geht

Ich kenne das auch so. Jeder erzählt es. Mich würde mal eine wirkliche 
Abhandlung darüber interessieren wieso es damit schlechter sein soll. 
Wirklich Nachteile und nicht nur den Millionsten der sage "das darf man 
nicht".

von Jürgen S. (jurs)


Lesenswert?

Paul Baumann schrieb:
> Das ist aber keine gute Idee, da mit GOTO herauszuspringen, weil das
> jede Menge "Trümmer" hinterläßt.
>
> Bei Bascom gibt es für solche Aktionen diese Befehle:
> EXIT FOR

Und aus einer dreifach geschachtelten for-Schleife nach diesem Muster 
springst Du mit Deinem Bascon dann wie heraus?
1
void nestedFor()
2
{
3
  for (int i=0;i<255;i++)
4
  {
5
    for (int j=0;j<255;j++)
6
    {
7
      for (int k=0;k<255;k++)
8
      {
9
        if (i==100 && j==20 && k==2) goto ende;
10
      }
11
    } 
12
  }
13
ende:  ;
14
}

Hast Du das "verschachtelt" in meinem Beitrag überlesen oder kannst Du 
bei Deinem BASCOM aus einer Dreifachverschachtelung vielleicht 
rausspringen indem Du schreibst
EXIT FOR FOR FOR
???

Natürlich gibt es auch unter C-Möglichkeiten, eine dreifach 
verschachtelte for-Schleife vorzeitig abzubrechen, ohne goto zu 
verwenden. Aber diese mehrfach verschachtelte for-Schleife wäre einer 
der wenigen Fälle, wo es mit goto eleganter als ohne goto möglich ist.

von Karl H. (kbuchegg)


Lesenswert?

132 schrieb:
> NoGoTo schrieb:
>> 3. weils mit schlechter geht
>
> Ich kenne das auch so. Jeder erzählt es. Mich würde mal eine wirkliche
> Abhandlung darüber interessieren wieso es damit schlechter sein soll.

Der von Jürgen weiter oben gepostete Spaghetti Code reicht dir noch 
nicht?

Was ist leichter zu verstehen? Der Code da oben, oder
1
int tausche_1_2(int i)
2
{
3
  if (i == 1)
4
    return 2;
5
  if (i == 2)
6
    return 1;
7
8
  Serial.print("Falscher Eingabewert: ");
9
  Serial.println(i);  
10
  return i;
11
}

oder für die, die sich am Mehrfach-Return stören
1
int tausche_1_2(int i)
2
{
3
  int Result;
4
5
  if (i == 1)
6
    Result = 2;
7
8
  else if (i == 2)
9
    Result = 1;
10
11
  else {
12
    Result = i;
13
    Serial.print("Falscher Eingabewert: ");
14
    Serial.println(i);
15
  } 
16
     
17
  return Result;
18
}

Leider ist Jürgens Code von weiter oben (der zur Abschreckung gedacht 
war) so ziemlich genau das, was bei einem durchschnittlichen Anfänger 
rauskommt, wenn er hemmungslos goto verwendet. Er will bestehenden Code 
nicht verändern, muss ihn aber erweitern, also springt er mit einem goto 
quer durch die Gegend.

Diese ganzen Konstrukte wie 'if', 'for', 'while', 'else' laufen letzten 
Endes immer intern auf einen goto hinaus. Nur verpacken sie das ganze 
so, dass dieser implizite goto in einer strukturierten Form vorkommt und 
in geordneten Bahnen verläuft. Quasi eine freiwillige 
Selbstbeschränkung. Gerade Schleifenkonstrukte sind dafür ja ein 
Paradebeispiel: Im Grunde alles durch andere Konstrukte und einem goto 
ersetzbar.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

BloedeFrage schrieb:
> Hallo, warum soll ich goto nicht nutzen?

Weil es viel bessere Lösungen gibt.

http://en.wikipedia.org/wiki/COMEFROM

;-)

von MCUA (Gast)


Lesenswert?

und PICs haben 'GOTO' (statt JMP) im ASM-Befehlssatz!

von Paul B. (paul_baumann)


Lesenswert?

Jürgen frug:
>Und aus einer dreifach geschachtelten for-Schleife nach diesem Muster
>springst Du mit Deinem Bascon dann wie heraus?

Bascom -mit "M" wie Matratze

Pass gut auf: Das ist nicht mein Bascom, es ist keine spezielle 
Version
für mich erstellt worden.

Solche Konstrukte wie Deines verwende ich nicht. Insofern ist mir das
vollkommen Titte!

Es ging darum, auf geordnete Weise aus einer Schleife 
herauszuspringen.

Paul

von Martin (Gast)


Lesenswert?

Es gab früher mal so etwas wie ein Struktogramm, und dort konnte man 
gotos halt nicht einpflegen zudem ist die Programmierung nicht 
"strukturiert"

Im Grunde spricht aber nichts gegen gotos. Ich verwende die auch des 
öfteren für Fehlerhandlingsituationen (wie oben auch schon von jemand 
anderen angedeutet).

von MCUA (Gast)


Lesenswert?

Es ist manchmal einfacher (zu lesen) von mehrerer Stellen aus mit GOTO 
an  (eine) bestimmte Stele springen, als bsp.weise etliche 
verschachtelte IFs zu benutzen.

von Rolf Magnus (Gast)


Lesenswert?

Gozo schrieb:
>>In der Tat gibt es wenige gute Anwendungsszenarien für goto, aber es
>>gibt sie!
> Was wäre denn ein gutes Beispiel? Das Abbrechen einer verschachtelten
> Schleife oder Fehlerbehandlung?

Genau das sind die beiden sinnvollen Anwendungsfälle, die ich kenne.

Paul Baumann schrieb:
> Das ist aber keine gute Idee, da mit GOTO herauszuspringen, weil das
> jede Menge "Trümmer" hinterläßt.

Was für Trümmer soll das denn hinterlassen?

Paul Baumann schrieb:
> Es ging darum, auf geordnete Weise aus einer Schleife herauszuspringen.

Eben nicht. Du antworetest auf:

Jürgen schrub:
>Nützlich ist "goto" ist heute noch ggf. beim Herausspringen aus mehrfach
>verschachtelten for-Schleifen, wenn man aus einer der inneren
>for-Schleifen direkt herausspringen möchte.

Einfach nur aus einer Schleife rausspringen kann man in C auch mit 
break.

von Walter Tarpan (Gast)


Lesenswert?

Gozo schrieb:
> Was wäre denn ein gutes Beispiel? Das Abbrechen einer verschachtelten
> Schleife oder Fehlerbehandlung?

Gerade bei der Fehlerbehandlung verwende ich regelmäßig gotos, wenn 
nachher noch "aufgeräumt" werden muß. Allerdings gehört Fehlerbehandlung 
immer noch zu den Dingen, zu denen ich wenig Informationen über 
sinnvolle Konzepte lesen konnte. So sieht bei mir z.B. eine typische 
Fehlerbehandlung aus:
1
/* Ganze Seite in EEPROM schreiben
2
 * Nur getestet fuer EEPROMS vom Typ 24C02, bei groesseren muss die
3
 * Speicheradresse in die I2C-Adresse eingerechnet werden. Nur einzelne
4
 * Speicherseiten (16 bytes) werden unterstuetzt.
5
 * Wegen des malloc duerfte es eine der langsamsten und speicherintensivsten
6
 * Funktionen des gesamten Projekts sein. */
7
static uint_fast8_t eeprom_write_page(uint8_t *buffer,uint8_t addr,uint8_t size)
8
{
9
  uint_fast8_t status, page_start, page_end;
10
  uint8_t * bigbuffer;
11
12
  // Block mit Groesse Null ist immer OK und wird nicht auf den Bus geschickt
13
  if(size==0) return ee_ok;
14
15
  // Pruefen, ob Block auf einer Seite liegt
16
  page_start = addr>>4;
17
  page_end   = (addr+size-1)>>4;
18
  if( !(page_start==page_end) ) {
19
    return ee_invalidAddress<<4;
20
  }
21
22
  // Pruefen, ob Block gueltige Adresse ist
23
  if(addr+size>EEPROM_SIZE_BYTES) {
24
    return ee_invalidAddress<<4;
25
  }
26
27
  bigbuffer = (uint8_t *) malloc(size+1);
28
  assert(bigbuffer!=NULL); // fehlgeschlagenes malloc ist nichts, wovon man
29
                           // sich sinnvoll erholen könnte.
30
  *bigbuffer = addr;
31
  memcpy(bigbuffer+1,buffer,size);
32
33
  // Kommando mit Stopbit senden
34
  status = I2C_Sendbuffer(EEPROM_I2C_DEVICE,EEPROM_I2C_ADDRESS,bigbuffer,\
35
      size+1,stop);
36
  free(bigbuffer);
37
  if (status!=0)
38
    goto error;
39
40
  return status; // = 0
41
42
  error:
43
  I2C_reset(EEPROM_I2C_DEVICE);
44
  return status;
45
}
Was man auf den ersten Blick sieht, ist daß hier das Paradigma des "nur 
ein Rückkehrpunkt" massiv verletzt ist - andererseits ist das ja auch 
keine "normale" Funktion, bei der das Funktionsergebnis wichtig ist, 
sondern wo nur die Nebenwirkungen gewollt werden und der 
Rückgabeparameter nur Hilfsmittel der Kontrolle ist.

Sprich: Ich kenne oft kein besseres Mittel zur Fehlerbehandlung als 
gotos.

Viele Grüße
W.T.

[EDIT: OK, gerade hier ist der einzige Zweck des gotos die 
Wiedererkennbarkeit, da die einzige Sprungquelle direkt davor liegt.]

von TriHexagon (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Jürgen schrub:
>>Nützlich ist "goto" ist heute noch ggf. beim Herausspringen aus mehrfach
>>verschachtelten for-Schleifen, wenn man aus einer der inneren
>>for-Schleifen direkt herausspringen möchte.
>
> Einfach nur aus einer Schleife rausspringen kann man in C auch mit
> break.

Aber nicht, wie er schreib, bei einer "mehrfach verschachtelten 
for-Schleife".

von Takao K. (takao_k) Benutzerseite


Lesenswert?

Es ist weitgehend egal. In PIC assembler muss man es andauernd 
verwenden.

Wichtig ist dass der Quelltext gut lesbar ist, wie dies erreicht wird 
ist egal.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Rolf Magnus schrieb:
> Gozo schrieb:
>>>In der Tat gibt es wenige gute Anwendungsszenarien für goto, aber es
>>>gibt sie!
>> Was wäre denn ein gutes Beispiel? Das Abbrechen einer verschachtelten
>> Schleife oder Fehlerbehandlung?
>
> Genau das sind die beiden sinnvollen Anwendungsfälle, die ich kenne.

In Java sind diese beiden Probleme durch labeled Statments gelöst. Damit
kann man mit break <label> beliebig verschachtelte Schleifen oder Blöcke
verlassen. Das break <label> stellt – wie auch alle anderen
Kontrollkonstrukte auch – ein verstecktes, aber eingeschränktes (und
damit weniger böses) goto dar und macht das goto fast völlig
überflüssig, weswegen es aus Java längst hinausgeschmissen wurde.

Auch andere etwas neuere Programmiersprachen bieten ähnliche Konstrukte
zum Verlassen verschachtelter Schleifen und zur übersichtlicheren
Fehlerbehandlung.

Es gibt aber noch ein paar weitere Anwendungen für Gotos. Zwei
Beispiele, die mir gerade einfallen:

- State-Machines: Hier werden mitunter Gotos für schnelle
  Zustandswechsel ohne eine explizite Zustandsvariable verwendet.

- Source-to-Source-Compiler: Die Generierung von goto-durchsetztem
  Spaghetti-Code ist oft einfacher als die Strukturierung des Codes in
  while…endwhile, for…endfor, if…else…endif usw. Da der generierte Code
  ohnehin nicht dazu gedacht ist, von Menschen gelesen zu werden, stellt
  das keinen großen Nachteil dar.

von MCUA (Gast)


Lesenswert?

>Es ist weitgehend egal. In PIC assembler muss man es andauernd
>verwenden.
Da sollte es JMP heissen, nicht Goto.
Sowas macht nur die von PIC!

von Georg (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Was für Trümmer soll das denn hinterlassen?

Das kommt auch wesentlich auf den Compiler an. Soweit ich weiss gibt es 
welche, die einem Goto automatisch (magisch) Aufräumcode voranstellen, 
es gibt aber auch welche, die einen aus einer Prozedur herausspringen 
lassen ohne den Stack zu bereinigen.

Nicht umsonst gibt es in manchen Firmen qualitätssichernde Vorschriften 
wie etwa die, dass eine Funktion immer nur einen Einsprungspunkt und 
einen Endpunkt haben darf.

In Assembler darf man sowieso alles, aber das ist keine Entschuldigung 
für schlecht strukturierte Programme. Und wenn man tricksen muss, etwa 
aus einem Unterprogramm direkt in ein anders springen, sollte man das 
sorgfältig kommentieren, aber noch besser es sein lassen.

Georg

von Mladen G. (mgira)


Lesenswert?

Yalu X. schrieb:
> In Java sind diese beiden Probleme durch labeled Statments gelöst. Damit
> kann man mit break <label> beliebig verschachtelte Schleifen oder Blöcke
> verlassen. Das break <label> stellt – wie auch alle anderen
> Kontrollkonstrukte auch – ein verstecktes, aber eingeschränktes (und
> damit weniger böses) goto dar und macht das goto fast völlig
> überflüssig, weswegen es aus Java längst hinausgeschmissen wurde.

.. in Java sollte man break labels auch vermeiden wenn moeglich, weil es 
eben so nah am goto ist ;)

Braucht man alles auch nicht wenn der Code sauber strukturiert ist, d.h. 
keine geschachtelten Schleifen bzw. keine anderen Kontrollstrukturen die 
direkt geschachtelt sind.
Jede Schleife in eine eigene Methode, dann reicht in 99% der Faelle ein 
return.

von Peter II (Gast)


Lesenswert?

Mladen G. schrieb:
> Braucht man alles auch nicht wenn der Code sauber strukturiert ist, d.h.
> keine geschachtelten Schleifen bzw. keine anderen Kontrollstrukturen die
> direkt geschachtelt sind.

wenn man z.b Bilddaten mit X und Y bearbeitet. Dann sind geschachtelten 
Schleifen sehr wohl sinnvoll. Dafür extra eine Funktion aufrufen ist 
wohl nicht immer die Lösung.

Außerdem ist eine extra Funktion auch keine Lösung, dann damit hat man 
genau das gleiche Problem
1
for( x ... ) {
2
   for( y ... ) {
3
       if ( ... )
4
          goto ende;
5
   }
6
}
7
:ende

mit einer Funktion geht das auch nicht sinnvoller
1
for( x ... ) {
2
   if ( foo( x ) == 0 )
3
       break;
4
   }
5
}

dann kann ich auch mit einer extra variable arbeiten
1
bool doExit = false;
2
for( x ... ) {
3
   for( y ... ) {
4
       if ( ... ) {
5
          doExit = true;
6
          break;
7
   }
8
   if ( doExit ) 
9
      break;
10
}


für mich die die goto lösung die übersichtlichste und vermutlich auch 
die schnellste.
Die Version mit der Extra Funktion ist die langsamste.

Warum sollte man auf ein Sprachfeature verzichten, wenn man damit kurzen 
und schnellen code schreiben kann?

von Mladen G. (mgira)


Lesenswert?

Peter II schrieb:
> wenn man z.b Bilddaten mit X und Y bearbeitet. Dann sind geschachtelten
> Schleifen sehr wohl sinnvoll. Dafür extra eine Funktion aufrufen ist
> wohl nicht immer die Lösung.

KOmmt auf den Kontext an.
Bei C etc. pp. mag das stimmen.
Bei Java gibt es absooluit keinen Grtund ekine eigenen Methode dafuer zu 
nehmen, siehe auch "Clean Code" von Bob Martin dazu..

Peter II schrieb:
> für mich die die goto lösung die übersichtlichste und vermutlich auch
> die schnellste.
> Die Version mit der Extra Funktion ist die langsamste.

In C vielleicht.. in Java sieht das anders aus, da kommt der JIT/Hotspot 
besser mit kleinen Methoden zurecht.
Ist aber voreilige Optimierung, in Java sollte definitiv der Quellcode 
im vordergrund stehen, nicht Pseudo Optimierungen.

Peter II schrieb:
> Warum sollte man auf ein Sprachfeature verzichten, wenn man damit kurzen
> und schnellen code schreiben kann?

Weil der Code schlecht zu lesen und warten ist.

von Peter II (Gast)


Lesenswert?

Mladen G. schrieb:
>> Warum sollte man auf ein Sprachfeature verzichten, wenn man damit kurzen
>> und schnellen code schreiben kann?
>
> Weil der Code schlecht zu lesen und warten ist.

klar wenn du nie goto verwendest, kannst du den code auch nicht warten. 
Bei anderen gehört es einfach zur Sprache dazu und ist genauso normal 
wie der "?" Operator, und diese Leute haben kein Problem mit der 
Wartung.

von Mladen G. (mgira)


Lesenswert?

Peter II schrieb:
> klar wenn du nie goto verwendest, kannst du den code auch nicht warten.
> Bei anderen gehört es einfach zur Sprache dazu und ist genauso normal
> wie der "?" Operator, und diese Leute haben kein Problem mit der
> Wartung.

Ich hatte noch nie das Beduerfnis goto zu verwenden, wozu auch?
Sehe keinen einzigen nutzen darin, ausser dass es den Code schlechter 
macht.

"Andere Leute" finden zB. auch PHP und Perl super, ich nicht.

von Peter II (Gast)


Lesenswert?

Mladen G. schrieb:
> Ich hatte noch nie das Beduerfnis goto zu verwenden, wozu auch?
> Sehe keinen einzigen nutzen darin, ausser dass es den Code schlechter
> macht.
Das es eine code schlechter macht ist ja Ansichtssache. Andere finden 
ihn dann besser.

Wenn du aber jeden code mit goto als grundsätzlich schlecht Betrachtest 
macht eine weiter Diskussion keine sinn.

http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/

von Mladen G. (mgira)


Lesenswert?

Peter II schrieb:
> Wenn du aber jeden code mit goto als grundsätzlich schlecht Betrachtest
> macht eine weiter Diskussion keine sinn.

Wie gesagt, im Kontext Java ist das immer (fast) immer schlecht, wobei 
es ja in Java nur die break Labels gibt und ich diese dann verteufele ;)
goto ist in Java zwar reserviert, aber nciht belegt.

Dein Link zeigt C, da ist das eben ein anderer Kontext.

von Alexander B. (leuchte)


Lesenswert?

Wobei man jetzt auch argumentieren kann, dass das Auslagern von 
verschachtelten Schleifen in eigene Funktionen den ansonsten knackigen 
Algorithmus zerfleddert und er dadurch wiederum schlecht zu lesen und zu 
warten ist. Kommt wohl auf den Einzelfall an ...

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mladen G. schrieb:
> .. in Java sollte man break labels auch vermeiden wenn moeglich, weil es
> eben so nah am goto ist ;)
> ...
> Jede Schleife in eine eigene Methode, dann reicht in 99% der Faelle ein
> return.

Für mein Empfinden ist ein Return aus einer (evtl. verschachtelten)
Schleife schlechterer Stil als ein entsprechender Break, da letzterer
zwar eine oder mehrere Blockgrenzen, der Return aber zusätzlich noch
eine Methodengrenze überspringt.

Dass des von vielen Java-Programmieren anders gesehen wird, liegt
vielleicht auch daran, dass die break-<label>-Anweisungen und die Labels
selbst syntaktisch stark den Gotos bzw. den Labels in C ähneln.
Semantisch gesehen sind aber wesentlich restriktiver.

PHP verwendet beim break statt der Labels eine Zahl, die angibt, um
wieviele Ebenen beim Verlassen von verschachtelten Schleifen nach oben
gesprungen wird. Das gefällt mir syntaktisch besser, hat aber den
Nachteil, dass man bei langen Schleifenrümpfen nicht sofort sieht,
welche der Schleifen denn nun tatsächlich beendet werden und welche noch
weiterlaufen.

von Mladen G. (mgira)


Lesenswert?

Yalu X. schrieb:
> Für mein Empfinden ist ein Return aus einer (evtl. verschachtelten)
> Schleife schlechterer Stil als ein entsprechender Break, da letzterer
> zwar eine oder mehrere Blockgrenzen, der Return aber zusätzlich noch
> eine Methodengrenze überspringt.

Wenn die Methode nur diese eine Schleife enthaelt, ist es "sauberer".

Die Clean Code Regeln aus Bob Martins Buch machen Sinn wenn man sie alle 
im Kontext sieht.
zB ist es gar kein Problem mehrere returns in einer einzigen Methode zu 
haben, denn Methoden haben auch sehr kurz zu sein, wieviele returns 
bekommt man in 3-5 Zeilen unter? ;)

Alexander B. schrieb:
> Wobei man jetzt auch argumentieren kann, dass das Auslagern von
> verschachtelten Schleifen in eigene Funktionen den ansonsten knackigen
> Algorithmus zerfleddert und er dadurch wiederum schlecht zu lesen und zu
> warten ist. Kommt wohl auf den Einzelfall an ...

Mag sein dass es im Einzelfall anders ist, aber dier generelle Regel nur 
eine einzige "Einrueckung" pro Methode zu haben funzt, Ausnahmen fuer 
spezielle Algorythmen (die man in Java mit der Lupe suchen muss) kann 
man ja machen.

von Adolf S. (juppe)


Lesenswert?

In der Batch-Programmierung ist das gang und gäbe, weil man dort ohne 
GOTO nicht weiterkommt:
http://www.robvanderwoude.com/goto.php

Spaghetti mit Tomatensoße

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

BloedeFrage schrieb:
> GENAU aus dem Grund habe ich die Frage gestellt. Und habe jetzt,
> zumindest ein paar, brauchbare Einschätzungen erhalten. Es geht also vor
> allem um die Lesbarkeit, welche durch (schwer nachzuvollziehende)
> Sprünge leidet. Richtig?

Nein, nicht wirklich. Es gab historische Gründe.

Zu der Zeit, als C aufkam, gab es massenweise Homecomputer, auf denen 
ein residenter Basic-Interpreter werkelte. Eher "richtige" Computer, wo 
CP/M drauf lief, waren teuer bis unerschwinglich.

Der Weg, den man also auf seinem Homecomputer einschlagen mußte, um 
irgend ein Programm zum Laufen zu bekommen war also, erstmal Basic zu 
lernen und zu benutzen. Basic war eine Sprache, die sehr 
zeilennummernorientiert war. Also z.B. ein Unterprogramm-Aufruf hieß 
z.B. GOSUB 1000 wobei 1000 die Zeilennummer war. Genauso ging es mit 
GOTO 1005 oder so. Schau dir mal ELIZA.BAS an, dann verstehst du wie das 
damals ging.

Für ganz einfache Programme war das alles ausreichend, aber nicht für 
größere komplexere Programme. Man kann in C auch so ähnlich schreiben 
wie in Basic - genauso, wie man auch z.B. in fast jeder 
Programmiersprache so ähnlich schreiben kann wie in Fortran.. ;-)

Nun, um nun all die jungen Basic-gewöhnten angehenden Programmiereriche 
umzuerziehen, wurde eben damals die Parole formuliert, in C niemals goto 
zu benutzen, bei Strafe der Exkommunikation oder Kielholen oder was auch 
immer.

Ja, DAMALS. Mittlerweile kennt kaum ein junger Strolch noch Basic, aber 
der Drill der damaligen Gulags hält sich weiter in den Köpfen und hat 
abenteuerliche Workarounds beschert. Ein häufiges Beispiel ist while(1). 
Eigentlich ist sowas wie while ja eine bedingte Schleife und auch genau 
dafür gedacht. Daß man sie mit while(1) quasi entartet hat, bloß um ein 
simples goto zu vermeiden, zeigt, was für Verrenkungen sich immer bei 
dogmatischem Drill einstellen.

Laß dich also von beschränkten Dogmatikern nicht einschüchtern, sondern 
verwende eben auch goto, wo es einen echten Sinn ergibt. Das ist 
tatsächlich nicht wirklich häufig, aber es kommt vor. Ein simples 
Beispiel ist die Grundschleife bei Mikrocontrollern:
int main (void)
{ initialisiere();
  immerzu:
    machedies();
    machedas();
    machenochwas();
  goto immerzu;
}

Wenn man das mit einem while(1) formuliert, dann meckern manche 
Compiler, daß main ja gar kein Ergebnis zurückgibt - zu Recht (im 
Prinzip). Also findet man bei solchen Strategen nach der Endlosschleife 
noch ein return 0 oder so, um den schieren Formalismus zu befriedigen.

W.S.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mladen G. schrieb:
> zB ist es gar kein Problem mehrere returns in einer einzigen Methode zu
> haben, denn Methoden haben auch sehr kurz zu sein, wieviele returns
> bekommt man in 3-5 Zeilen unter? ;)

Einverstanden.

Wenn die Methoden aber so kurz sind, muss man verschachtelte Schleifen
auf mehrere Methoden verteilen (das hast du weiter oben wahrscheinlich
auch so gemeint).

Wie kannst du dann aber von der innersten Schleife (die sich in einer
Methode befindet) aus die äußerste (in einer anderen Methode) verlassen?
Das geht doch nur dadurch, dass jede Methode ein entsprechendes Flag
zurückgibt, das in der Schleife der aufrufenden Methode abgefragt und
ggf. weitergereicht wird, und das über mehrere Ebenen.

Das wird doch beliebig kompliziert und trägt sicher nicht zur besseren
Lesbarkeit des Programms bei. Oder wie würdest du bspw. folgende Methode
in drei Methoden mit jeweils einer Schleife aufdröseln?
1
  int loop() {
2
    int x=0, y=0, z=0;
3
4
    loopz:
5
    for(z=0; z<10; z++) {
6
      for(y=0; y<10; y++) {
7
        for(x=0; x<10; x++) {
8
          if(condition(x, y, z))
9
            break loopz;
10
        }
11
      }
12
    }
13
    return x + y + z;
14
  }

von Takao K. (takao_k) Benutzerseite


Lesenswert?

Georg schrieb:
> Rolf Magnus schrieb:
>> Was für Trümmer soll das denn hinterlassen?
>
> Das kommt auch wesentlich auf den Compiler an. Soweit ich weiss gibt es
> welche, die einem Goto automatisch (magisch) Aufräumcode voranstellen,
> es gibt aber auch welche, die einen aus einer Prozedur herausspringen
> lassen ohne den Stack zu bereinigen.
>
> Nicht umsonst gibt es in manchen Firmen qualitätssichernde Vorschriften
> wie etwa die, dass eine Funktion immer nur einen Einsprungspunkt und
> einen Endpunkt haben darf.
>
> In Assembler darf man sowieso alles, aber das ist keine Entschuldigung
> für schlecht strukturierte Programme. Und wenn man tricksen muss, etwa
> aus einem Unterprogramm direkt in ein anders springen, sollte man das
> sorgfältig kommentieren, aber noch besser es sein lassen.
>
> Georg

Zeig mir mal einen modernen Compiler der es erlaubt aus der Prozdur 
(Pascal?) herauszuspringen. Das geht in C schon mal gar nicht.

In Embedded C bekommst du sofort einen Absturz wenn der Stack nicht 
stimmt.

Ausserdem koennen C funktionen durchaus viele Endpunkte haben- je nach 
Bedingung wird einer zuerst aktiv. Dadurch wird der Quelltext kuerzer 
z.b.
1
if(wert==1)return(0);else return(0xff);

kannste in dem Fall auch
1
return(wert);
 verwenden, aber es ist nur ein Beispiel, vielleicht ist Wert obskur und 
soll bereits in der Funktion umgesetzt werden.

Denk mal darueber nach:
1
i=7;
2
reloop:;
3
*(ch++)=0;if((i--)>0)goto reloop;

bewirkt auch nichts anderes als eine for schleife.

Mit dem Unterschied dass bei for die Bedingung zuerst abgefragt wird, 
hier wird der code innerhalb zumindest einmal abgearbeitet.

ausserdem, wenn du es aus irgeneinem obskurem Grund willst, kannst du 
den Wiederholpunkt auch noch von woanders anspringen. Das kann schon 
Sinn machen wenn du es mit Bitmaps zu tun hast, die u.U. alignment 
erfordern, u.U. aber auch nicht. Mit FOR musst du dann den Code nochmal 
wiederholen.

Ja klar mit zu vielen GOTOs versaust du dein Programm (zumindest den 
Quelltext).

von Mladen G. (mgira)


Lesenswert?

Yalu X. schrieb:
> Wenn die Methoden aber so kurz sind, muss man verschachtelte Schleifen
> auf mehrere Methoden verteilen (das hast du weiter oben wahrscheinlich
> auch so gemeint).
>
> Wie kannst du dann aber von der innersten Schleife (die sich in einer
> Methode befindet) aus die äußerste (in einer anderen Methode) verlassen?
> Das geht doch nur dadurch, dass jede Methode ein entsprechendes Flag
> zurückgibt, das in der Schleife der aufrufenden Methode abgefragt und
> ggf. weitergereicht wird, und das über mehrere Ebenen.
>
> Das wird doch beliebig kompliziert und trägt sicher nicht zur besseren
> Lesbarkeit des Programms bei. Oder wie würdest du bspw. folgende Methode
> in drei Methoden mit jeweils einer Schleife aufdröseln?
>
>
1
>   int loop() {
2
>     int x=0, y=0, z=0;
3
> 
4
>     loopz:
5
>     for(z=0; z<10; z++) {
6
>       for(y=0; y<10; y++) {
7
>         for(x=0; x<10; x++) {
8
>           if(condition(x, y, z))
9
>             break loopz;
10
>         }
11
>       }
12
>     }
13
>     return x + y + z;
14
>   }
15
>

Das ist ein Beispiel, bei dem es wohl besser waere es nicht in einzelne 
Methoden aufzuteilen.

Muss aber ehrlich dazu sagen, dass ich dieses Konstrukt in 14 Jahren als 
Hauptberuflicher Java Entwickler noch nie brauchte.

Mit ist schon klar dass es wohl immer Ausnahmen geben wird, deswegen 
sehe ich auhc kein Problem mit einer Regel die sagt: "break labels 
sollten vermieden werden", weil es eben in den meisten Faellen wahr ist.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Ein aus meiner Sicht wichtiger Aspekt ist (neben der in einigen oben 
beschriebenen Fällen der besseren Lesbarkeit und klareren Struktur) goto 
erlaubt, kritischen Code sehr kompakt und sehr effizient zu schreiben 
bzw. zu kompilieren. Dabei geht es z.B. darum, dass der resultierende 
Code möglichst kurz ist (Cache footprint) und der wahrscheinlichste 
Codepfad sehr geradlinig ohne Sprünge abläuft (Prefetch queue /  branch 
prediction). Ein beliebter Trick ist dabei eben, in eine geradlinige 
(Assebler-) Codesequenz an beliebiger Stelle mit Goto einspringen zu 
können.

Dafür ist goto ein gutes Hilfsmittel, aber dafür gibt es noch andere 
Tricks (likely/unlikely bedingungen) und andere "angeblich" sehr böse 
sachen (switch/case fallthrough)

: Bearbeitet durch User
von Daniel F. (df311)


Lesenswert?

Peter II schrieb:
> bool doExit = false;
> for( x ... ) {
>    for( y ... ) {
>        if ( ... ) {
>           doExit = true;
>           break;
>    }
>    if ( doExit )
>       break;
> }

je nachdem wie die schleifen aufgebaut sind (z.b. eine matrix 
durchlaufen oder sowas in der richtung) könnte man das ganze auch 
dadurch abbrechen, dass man anstatt doExit = true die einzelnen 
abbruchbedingungen der schleifen quasi erzwingt.

sowas in der art
1
for(uint8_t x = 0; x < 128; x++) {
2
  for(uint8_t y = 0; y < 128; <++) {
3
    if(something) {
4
      x = UINT8_MAX;
5
      y = UINT8_MAX;
6
      break;
7
    }
8
  }
9
}

bitte nicht auf die konstanten festnageln - es geht ja nur ums 
prinzip...

von Yalu X. (yalu) (Moderator)


Lesenswert?

Mladen G. schrieb:
> Das ist ein Beispiel, bei dem es wohl besser waere es nicht in einzelne
> Methoden aufzuteilen.
>
> Muss aber ehrlich dazu sagen, dass ich dieses Konstrukt in 14 Jahren als
> Hauptberuflicher Java Entwickler noch nie brauchte.

Ein ganz ähnliches Konstrukt ergibt sich, wenn man bspw. in einem
mehrdimensionalen Array ein Element mit einer bestimmten Eigenschaft
suchen möchte. So etwas läuft einem doch öfter über den Weg.

Manche Programmiersprachen bzw. Bibliotheken bieten aber auch die
Möglichkeit, verschachtelte Schleifen wie die obigen eben zu büglen, so
dass nur noch eine einzelne Schleife übrig bleibt, die mit einem
gewöhnlichen break verlassen werden kann. In python sähe das bspw. so
aus:
1
from itertools import product
2
3
def loop():
4
  for z, y, x in product(range(10), range(10), range(10)):
5
    if condition(x, y, z):
6
      break
7
  return x + y + z

Das Stichwort dazu lautet "Iteratoren", die es m.W. in ähnlicher Form
auch in der Java-Bibliothek gibt. Vielleicht kann man dort mit den
leidigen verschachtelten Schleifen ähnlich verfahren wie in Python.

Will man auch noch auf den break verzichten, der ja immer noch ein
Bisschen Goto-Charakter hat, kann man das Ganze in Python auch als
Generator-Comprehension schreiben:
1
def loop():
2
  return next((x+y+z) for z in range(10) for y in range(10) for x in range(10) if condition(x, y, z))

Diese Schreibweise hat Python übrigns von Haskell geerbt, wo das Genze
noch etwas kompakter geschrieben wird:
1
loop = head [x+y+z | z<-[0..9], y<-[0..9], x<-[0..9], condition x y z]

Da in Haskell die Liste ein Spezialfall einer Monade ist, kann man die
List-Comprehension (der Teil nach "head") auch im Monadenstil schreiben:
1
loop = head $ do
2
  z <- [0..9]
3
  y <- [0..9]
4
  x <- [0..9]
5
  guard (condition x y z)
6
  return (x + y + z)

Das sieht zwar nicht arg viel anders aus als das vorherige Beispiel,
aber die mit <-[0..9] endenen Zeilen sind jetzt getrennte Actions. Da
sie alle gleich aussehen, liegt es nahe, sie in eine Art Schleife zu
packen:
1
loop = head $ do
2
  [x, y, z] <- replicateM 3 [0..9]
3
  guard (condition x y z)
4
  return (x + y + z)

Die Zahl der verschachtelten Schleifen im ursprünglichen Java-Code
taucht hier in der zweiten Zeile als numerische Konstante (3) auf. Man
kann sie durch eine Variable n ersetzen, wenn man gleichzeitig dafür
sorgt, dass die Funktion condition und die Summe in der letzten Zeile
mit einer variablen Zahl von Operanden klar kommen. Das geschieht am
einfachsten dadurch, dass man die Variablen x, y und z zusammen durch
eine Liste (xs) mit n Elementen ersetzt. Das sieht dann so aus:
1
loop n = head $ do
2
  xs <- replicateM n [0..9]
3
  guard (condition xs)
4
  return (sum xs)

Dieser Code tut tatsächlich im Wesentlichen das Gleiche wie der
ursprüngliche Java-Code:
1
  int loop() {
2
    int x=0, y=0, z=0;
3
4
    loopz:
5
    for(z=0; z<10; z++) {
6
      for(y=0; y<10; y++) {
7
        for(x=0; x<10; x++) {
8
          if(condition(x, y, z))
9
            break loopz;
10
        }
11
      }
12
    }
13
    return x + y + z;
14
  }

Er ist aber kürzer und die Anzahl der verschachtelten impliziten
Schleifen ist variabel und kann über das Funktionsargument n gesteuert
werden. Der break im Java-Programm verbirgt sich implizit in der
head-Funktion, die das erste Element der durch den do-Block erzeugten
Liste zurückgibt. Da die restlichen Elemente nirgend benutzt werden,
werden sie auch nicht berechnet, was einem Abbruch der verschachtelten
Suchschleife gleichkommt.

Nicht nur der break, sondern auch die expliziten For-Schleifen sind
verschwunden. Sie sind irgendwo in die Tiefen der Laufzeitbibliothek
verlagert worden, ähnlich wie die impliziten Gotos der For-Schleifen in
Java in den Maschinencode der VM verlagert werden, wo sie niemanden
stören.

Diese Beispiel zeigt, dass man explizite Sprünge (Gotos) schrittweise
durch weniger explizite Sprünge ersetzen kann, bis am Schluss auf
Quellcodeebene nur noch linearer Code übrig bleibt. Linearer Code ist
das genaue Gegenteil vom Spaghetti-Code und deswegen nur minimal
fehleranfällig.

Bei der schrittweisen Umwandlung wurde sogar ohne großen Zusatzaufwand
noch Funktionalität hinzugewonnen (Iteration von n statt nur 3
Variablen), die sich mit den klassischen aus der strukturierten
Programmierung bekannten Konstrukten nur schwer realisieren lässt.

Trotzdem hat es sich ein Verückter nicht nehmen lassen, auch für Haskell
ein Goto nachzurüsten:

  http://hackage.haskell.org/package/GotoT-transformers-1.0/docs/Control-Monad-Trans-Goto.html

Ich vermute aber, dass es sich hier primär um einen Fall von "Und es
geht doch" ohne allzu viel praktischen Nutzen handelt. Auch für Python
hat jemand so ein Proof-of-Concept-Goto entwickelt. Es spricht immerhin
für die Mächtigkeit einer Programmiersprache, wenn so etwas mit
gewöhnlichen Sprachmitteln ohne Manipulation des Compilers und ohne die
Verwendung eines speziell dafür angefertigten Präprozessors möglich ist.

von Mike (Gast)


Lesenswert?

Martin schrieb:
> Es gab früher mal so etwas wie ein Struktogramm

Die Nassi-Shneiderman-Diagramme haben aus gutem Grund ihren Eingang in 
die DIN (DIN 66261) gefunden.

Versuch da mal ein "goto" rein zu strukturieren. Ein "Goto" machte fast 
jede Programmstruktur unberechenbar (Ausnahme vielleicht das "Exit").

von Konrad S. (maybee)


Lesenswert?

@Yalu
Ginge das auch mit einem range von 10000? Oder anders gefragt: Muss das 
product im Speicher Platz haben?

von Karl Käfer (Gast)


Lesenswert?

Hallo Konrad,

Konrad S. schrieb:
> Ginge das auch mit einem range von 10000?

Jaein.

> Oder anders gefragt: Muss das product im Speicher Platz haben?

Jaein.

Wenn man es wie Yalu mit der range()-Funktion macht, dann müssen die 
drei von range zurückgegebenen Listen Platz im Speicher haben. product() 
würde dann aber trotzdem jeweils über die Listen iterieren und einen 
Iterator bereitstellen, der jeweils nur das akutelle Ergebnis berechnet, 
und dann braucht auch nur das aktuelle Ergebnis Platz im Speicher.

Dem geneigten Pythonista steht deswegen neben der Funktion range() auch 
noch die Funktion xrange() zur Verfügung, die nicht wie range() eine 
Liste, sondern einen Iterator zurückgibt. Wenn man also anstelle von 
Yalus Code
1
product(xrange(10), xrange(10), xrange(10))
 benutzt, dann wird bei jedem Aufruf von product() immer nur das 
aktuelle Ergebnis berechnet und im Speicher allokiert.

HTH,
Karl

von Takao K. (takao_k) Benutzerseite


Lesenswert?

Ja klar nun starte ich Eclipse oder MPLABX auf meinem 1GB netbook, was 
sind schon 1GB, warte 3 Minuten, die Eingabe ist blockiert, irgenwann 
gehts dann sogar, umschalten, naja, warte 20 Sekunden.

desgleichen mit Skype und Web hotmail. Die brauchen FLASH und 
Silverlight um dir Werbung zu zeigen die du immer wieder aus versehen 
anclickst.

Ist dass nicht so eine Art GOTO gegen deinen Willen? Du clickst die 
Scroll Leiste, aber der Browser macht ein neues Fenster auf mit Skype 
Werbungsseiten die nutzlos sind und die du schon 20 mal gesehen hast.

Aber sei dir gewiss, der Source code enthaelt garantiert kein einziges 
GOTO.

Also ersteht es irgenwie wieder auf? Ach ja, liegt wohl daran das 1GB 
zuwenig Speicher ist.

Mit GOTO ist es halt so eine Sache, es ist ein linearer Ablauf, du 
befindest dich bei Punkt A, und gehst zu Punkt B aus irgeneinem Grund.

Im realen Leben kannst du das nicht vermeiden, oder wie ist da der 
objektorientierte Ansatz?

von PittyJ (Gast)


Lesenswert?

Anfänger sollten möglichst viel goto verwenden. Denen sollte man die 
Schleifen gar nicht beibringen.

Wenn viele goto's verwendet werden, dann habe ich einen sicheren 
Arbeitsplatz bis zur Rente.


Ansonsten bin ich die letzten 25 Jahre goto-frei ausgekommen, und ich 
habe wirklich viel Code geschrieben.

von Christian B. (casandro)


Lesenswert?

Naja wie schon oben beschrieben gibt es Anwendungen wo Goto sinnvoll 
ist.

Für so richtig eleganten Code braucht man aber natürlich das Comefrom, 
das in vielen Sprachen drin ist.

von Rolf Magnus (Gast)


Lesenswert?

Daniel F. schrieb:
> je nachdem wie die schleifen aufgebaut sind (z.b. eine matrix
> durchlaufen oder sowas in der richtung) könnte man das ganze auch
> dadurch abbrechen, dass man anstatt doExit = true die einzelnen
> abbruchbedingungen der schleifen quasi erzwingt.

Das ist aber ein fieser Trick, den ich nicht nutzen würde, nur um goto 
vermeiden zu können. Man spart sich zwar die unschöne Statusvariable, 
die man auf jeder Ebene nochmal extra abfragen muss, aber elegant ist 
das auch nicht. Genau das ist die Sache: Man kann goto immer irgendwie 
vermeiden, aber das Ziel sollte nicht sein, goto um jeden Preis 
wegzubekommen, sondern guten Code zu schreiben. Und manchmal (wenn auch 
selten) ist der mit goto besser.

Mike schrieb:
> Ein "Goto" machte fast jede Programmstruktur unberechenbar (Ausnahme
> vielleicht das "Exit").

Was soll denn daran unberechnenbar sein? goto springt ja nicht 
willkürlich irgendwo hin.

@Takao K.:
Bekanntlich ist goto ja auch für die globale Erwärmung, die Vogelgrippe 
und natürlich dafür, daß in China so viele Reissäcke umfallen, 
verantwortlich.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Konrad S. schrieb:
> @Yalu
> Ginge das auch mit einem range von 10000? Oder anders gefragt: Muss das
> product im Speicher Platz haben?

Karl hat schon fast alles dazu geschrieben. Um über alle Tripel in
product(range(10000), range(10000), range(10000)) zu iterieren, braucht
man also Speicherplatz für 3·10000=30000 Elemente.

Karl Käfer schrieb:
> Wenn man also anstelle von Yalus Codeproduct
>
>  (xrange(10), xrange(10), xrange(10))
>
> benutzt, dann wird bei jedem Aufruf von product() immer nur das
> aktuelle Ergebnis berechnet und im Speicher allokiert.

Das stimmt (leider) nicht ganz.

Zum einen ist in Python 3 range das, was in Python 2 xrange war. Es
liefert also keine Liste, sondern ein Objekt, aus dem sich ein Iterable
gewinnen lässt, das unabhängig vom Argument nur wenig Speicher belegt.
xrange ist deswegen in Python 3 obsolet. Wenn man die range-Funktion von
Python 2 benötigt, kann man diese mit list(range(n)) nachbilden.

Zum anderen (und jetzt kommt das "leider") erzeugt die product-Funktion
aus jedem der Argumente erst einmal eine Liste. Zumindest beim ersten
Argument ist das für mich nicht ganz nachvollziehbar, da dieses Iterable
nur ein einziges Mal durchlaufen wird und es deswegen keine Vorteile
bringt, die einzelnen Werte zu speichern.

Deswegen darf auch keines der Argumente unbegrenzt iterieren, obwohl das
beim ersten Argument (das der äußersten Schleife entspricht) schon
manchmal wünschenswert wäre und in anderen Sprachen, wie z.B. Haskell
auch tatsächlich möglich ist. Dort liefert
1
[[x,y] | x<-[0..], y<-[0..2]]

bzw.
1
sequence [[0..], [0..2]]

wie erwartet die endlose Liste
1
[[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2],[3,0],...]

Eine Produktfunktion für Python, deren Speicherbedarf unabhängig von der
Größe der übergebenen Iterables ist und die damit auch mit endlosen
Iterables zurechtkommt, könnte in ihrer einfachsten Form so aussehen:
1
def product2(*iterables):
2
  if iterables:
3
    for x in iterables[0]:
4
      for t in product2(*iterables[1:]):
5
        yield (x,) + t 
6
  else:
7
    yield ()

Sie ist aber im Vergleich zum Original langsamer, da dieses nicht in
Python, sondern in C programmiert ist.

von nicht"Gast" (Gast)


Lesenswert?

Moin,

sind ja ganz schön gruselige Goto Konstrukte, die hier aufschlagen.

Jürgen S. schrieb:
> void nestedFor()
> {
>   for (int i=0;i<255;i++)
>   {
>     for (int j=0;j<255;j++)
>     {
>       for (int k=0;k<255;k++)
>       {
>         if (i==100 && j==20 && k==2) goto ende;
>       }
>     }
>   }
> ende:  ;
> }

Wozu brauchts an der Stelle ein Goto?
1
void nestedFor()
2
 {
3
   for (int i=0;i<255;i++)
4
   {
5
     for (int j=0;j<255;j++)
6
     {
7
       for (int k=0;k<255;k++)
8
       {
9
         if (i==100 && j==20 && k==2) return;
10
       }
11
     }
12
   }
13
 }
schein mir an der Stelle übersichtlicher zu sein, da ich nicht noch 
extra einem Goto folgen muss um festzustellen, dass aus der Funktion 
gesprungen wird. Bei der zweiten Variante ist es sofort ersichtlich.

Walter Tarpan schrieb:
>   // anderer Code hier
>   if (status!=0)
>     goto error;
>
>   return status; // = 0
>
>   error:
>   I2C_reset(EEPROM_I2C_DEVICE);
>   return status;
> }
1
    if (status != 0)
2
    {
3
       I2C_reset(EEPROM_I2C_DEVICE);
4
    }
5
    return status;
Wäre an der Stelle auch zu übersichtlich und lesbar (am Rande, status 
ist als Name schlecht gewählt :)

W.S. schrieb:
> int main (void)
> { initialisiere();
>   immerzu:
>     machedies();
>     machedas();
>     machenochwas();
>   goto immerzu;
> }
>
> Wenn man das mit einem while(1) formuliert, dann meckern manche
> Compiler, daß main ja gar kein Ergebnis zurückgibt - zu Recht (im
> Prinzip). Also findet man bei solchen Strategen nach der Endlosschleife
> noch ein return 0 oder so, um den schieren Formalismus zu befriedigen.

Sollte der Compiler nicht bei dir auch meckern? du hast ja immerhin 
genau so eine Funktion, die einen Rückgabewert erwartet, der du keinen 
lieferst.

An der Stelle ist es aber warscheinlich egal, welches Konstrukt man 
verwendet ob while(true) oder for(;;) oder goto. Gegen Goto spricht nur 
die Andersartigkeit der Klammersetzung. Diese ist ja beim Goto 
einzigartig. So ein Konstrukt gibt es ja in C sonst nicht.

Ich meine:
1
int main()
2
{
3
   while(true)
4
   {
5
      // fancy stuff here
6
   }
7
}
8
9
gegenüber 
10
11
int main()
12
{
13
  label:
14
      // fancy stuff here
15
  goto label;
16
}

Zweiteres ist man normalerweise nicht gewohnt und muss genauer hin 
schauen. Das stört den Lesefluss doch erheblich. Besonders wenn man Goto 
normalerweise nicht benutzt.

Goto wird leider überwiegend verwendet um schlechtes Design zu 
kaschieren. Wenn man mein unbedingt ein Goto zu brauchen, sollte man 
lieber erst mal ein Refactoring anstoßen und erst wenn das nicht hilft 
Goto einsetzen.


Grüße,

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

nicht"Gast" schrieb:
> if (status != 0)
>     {
>        I2C_reset(EEPROM_I2C_DEVICE);
>     }
>     return status;
> Wäre an der Stelle auch zu übersichtlich und lesbar (am Rande, status
> ist als Name schlecht gewählt :)

genau sowas (aber in einer etwas anderen Form) kann lästige auswirkungen 
haben.

nehmen wir folgende Code-sequenz, erstmal in der "optimalen" Variante 
ohne Fehlerbehandlung:
1
tu_was();
2
tu_nochwas();
3
du_nochwas_drittes();
4
aufraeumen();

schäön sequentiell, keine Sprünge die dir die Pipeline flushen, da kann 
er wie auf dem geraden Autobahnstück mit 300 Sachen drüberbrettern.

nun kommt die lästige Fehlerbehandlung:
1
tu_was();
2
if (!ok) {
3
   cleanup();
4
   return -E_BE_HAPPY;
5
}
6
tu_nochwas();
7
if (!ok) {
8
   cleanup();
9
   return -E_DONT_WORRY;
10
}
11
tu_nochwas_drittes();
12
if (!ok) {
13
   cleanup();
14
   return -E_DONT_KNOW;
15
}
16
cleanup();
17
return 0;
ist schon überhaupt nicht mehr geradlinig, dauernde Sprünge (die man 
aber mit likely() etwas entschärfen kann), aber, und das ist den 
wenigsten bewusst: cleanup() wird schlimmstenfalls vom compiler viermal 
inline eingesetzt, damit vervierfacht sich der ICache-Footprint! (ncoh 
schlimmer und unübersichtlicher wirds wenn ich nicht eine cleanup() 
habe, sondern drei oder mehr verschiedene die je nachdem wie weit er 
gekommen ist, aufgerufen werden müssen oder auch nicht)

natürlich kann man das auch anders schreiben:
1
tu_was();
2
if(ok) {
3
   tu_nochwas();
4
   if (ok) {
5
       tu_nochwas_drittes();
6
   }
7
}
8
cleanup();

Das inline-problem ist zwar weg, aber übersichtlicher ists auch nciht, 
speziell wenn ich nicht drei sondern mehr solcher if()s habe bin ich 
irgendwann am rechten Bildschirmrand... verschiedene Cleanups sind auch 
schwer unterzubringen, und sequentiell ists auch nicht gerade...

Was ist so schlimm daran, die ursprüngliche "Autobahn" zu verwenden, und 
dort wo notwendig ein "goto out" einzubauen?

nicht"Gast" schrieb:
> Goto wird leider überwiegend verwendet um schlechtes Design zu
> kaschieren.

Na na na na....

von Mladen G. (mgira)


Lesenswert?

Yalu X. schrieb:
> Ein ganz ähnliches Konstrukt ergibt sich, wenn man bspw. in einem
> mehrdimensionalen Array ein Element mit einer bestimmten Eigenschaft
> suchen möchte. So etwas läuft einem doch öfter über den Weg.

Ich sag mal so: Ich weiss das andere das mal brauchten, selber ging mir 
das noch nie so.
Mehrdimensionale Arrays an sich sind etwas mit dem ich sehr selten 
direkt in Kontakt komme als Java Entwickler, zumnidest in meinem 
Bereich, das wird wohl auch der Gund sein warum ich ein break label noch 
nie brauchte.

von nicht"Gast" (Gast)


Lesenswert?

Michael Reinelt schrieb:
> nun kommt die lästige Fehlerbehandlung:tu_was();
> if (!ok) {
>    cleanup();
>    return -E_BE_HAPPY;
> }
> tu_nochwas();
> if (!ok) {
>    cleanup();
>    return -E_DONT_WORRY;
> }
> tu_nochwas_drittes();
> if (!ok) {
>    cleanup();
>    return -E_DONT_KNOW;
> }
> cleanup();
> return 0;

Schreib das doch mal mit gotos und zeig mir, dass das lesbarer ist.

Michael Reinelt schrieb:
> tu_was();
> if(ok) {
>    tu_nochwas();
>    if (ok) {
>        tu_nochwas_drittes();
>    }
> }
> cleanup();

Mein Gegenvorschlag:
1
if (    ! tuwas()
2
     || ! tuwasanderes()
3
     || ! tuwasdrittes())
4
   ){
5
   cleanup();
6
   return ging_nicht;
7
}
8
9
cleanup();
10
return ging;

wenn man bei tuwas() und co true für ging und false für ging nicht 
zurückgibt, ist es ein wenig Übersichtlicher. Allerdings war das 
Fehlerhandling ja schon immer der Hinkefuß von C. In C++ gibts ja 
Gottseidank Exceptions für so was.

Für die Nörgler: wenn tuwas() 0 zurückgibt, werden die weiteren 
Funktionen nicht ausgeführt, da das Ergebnis der logischen Verknüpfung 
fest steht.

von nicht"Gast" (Gast)


Lesenswert?

Michael Reinelt schrieb:
> nicht"Gast" schrieb:
>> Goto wird leider überwiegend verwendet um schlechtes Design zu
>> kaschieren.
>
> Na na na na....

Hab nicht geschrieben immer :). Die Beispiele hier im Thread bestätigen 
mich leider ein wenig.

von Thomas (Gast)


Lesenswert?

Gerade im Microcontrollerbereich ist die ROM-Größe oft limitiert.
Wenn es dann zu Ketten kommt, wie im Beispiel von Michael beschrieben, 
sammelt sich durch Fehlerhandling schnell einiger Code an.

Wer schon in schwierigen Situation war, am Ende des Projekts zu wenig 
ROM-Platz zu haben,kennt die Aktionen, die dann gestartet werden um das 
Projekt zu retten. Strukturierte Programmierung ohne Gotos bleibt dann 
mit als erstes auf der Strecke, wenn bereits zuvor vernünftig 
(platzsparend) progranmmiert wurde.

Nachteil ist natürlich der höhere Aufwand durch schwierigeres Testen. 
Wenn allerdings der Compiler (bei uns Keil-C) in einer höheren 
Optimierungsstufe betrieben wird, werden solche Aktionen teilweise auch 
vom Compiler eingefügt.

Aus meiner Sicht ist an derartigen Anpassungen nichts zu meckern, bei 
uns in der Firma ist es nur leider so, dass dieser Code unverändert 
immer wieder übernommen wird, auch wenn es keine Platzprobleme mehr 
gibt. Hier sollte man sich Gedanken machen, wie dies Optimierungen 
später einfach lokalisiert und rückgebaut werden können.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

nicht"Gast" schrieb:
> Schreib das doch mal mit gotos und zeig mir, dass das lesbarer ist.

fändest du weiter oben schon, aber bitte:
1
tu_was();
2
if (!ok) goto out;
3
tu_nochwas();
4
if (!ok) goto out;
5
du_nochwas_drittes();
6
out:
7
aufraeumen();

nicht"Gast" schrieb:
> if (    ! tuwas()
>      || ! tuwasanderes()
>      || ! tuwasdrittes())
>    ){
>    cleanup();

Einverstanden, geht aber nciht immer: tuwas() und co. sind in meinem 
Fall nicht als reine Funktionsaufrufe zu verstehen, sondern als 
(durchaus längere) Codesequenzen, die nicht so einfach einen Return-Wert 
haben

also eher so:
1
bereite_vor();
2
initialisiere();
3
berechne();
4
xxx();
5
hole_a()
6
if (!a) goto out;
7
tu_nochwas();
8
mach_was_mit_b();
9
x=a+b-27;
10
hallo=x(314)&0xl337;
11
if (hallo==0) goto out;
12
du_nochwas_drittes();
13
x();
14
y();
15
z();
16
out:
17
aufraeumen();

nebenbei:

nicht"Gast" schrieb:
> if (){
>    cleanup();
>    return ging_nicht;
> }
>
> cleanup();
> return ging;

2* Cleanup() ge-inlined :-(

von Georg (Gast)


Lesenswert?

Michael Reinelt schrieb:
> fändest du weiter oben schon, aber bitte:
> tu_was();
> if (!ok) goto out;
> tu_nochwas();
> if (!ok) goto out;
> du_nochwas_drittes();
> out:
> aufraeumen();

Wie wärs damit:
1
tu_was();
2
if (ok) then {
3
  tu_nochwas();
4
  if (ok) then {
5
    du_nochwas_drittes();
6
    }
7
  }
8
aufraeumen();

Ich hoffe ich habs richtig geschrieben, im Moment mache ich Pascal, aber 
man sieht wohl was gemeint ist.

Georg

von Puh der Bär (Gast)


Lesenswert?

Michael Reinelt schrieb:
> ..
> if (!a) goto out;
> tu_nochwas();
> mach_was_mit_b();
> x=a+b-27;
> hallo=x(314)&0xl337;
> if (hallo==0) goto out;
> du_nochwas_drittes();
> x();
> y();
> z();
> out:
> aufraeumen();

Alter, das ist ganz übler Basic-Spaghetti-Code. Besser ist hier eine if 
else Sequenz.

von nicht"Gast" (Gast)


Lesenswert?

Michael Reinelt schrieb:
> nicht"Gast" schrieb:
>> if (){
>>    cleanup();
>>    return ging_nicht;
>> }
>>
>> cleanup();
>> return ging;
>
> 2* Cleanup() ge-inlined :-(

:) kleine Umänderung
1
   bool allesGut = false;
2
   if ( aktionginggut )
3
   {
4
       allesGut = true;
5
   }
6
   cleanup();
7
   return allesGut;
würd ich echt lieber so schreiben, als Gotos einzubauen

Michael Reinelt schrieb:
> also eher so:bereite_vor();
> initialisiere();
> berechne();
> xxx();
> hole_a()
> if (!a) goto out;
> tu_nochwas();
> mach_was_mit_b();
> x=a+b-27;
> hallo=x(314)&0xl337;
> if (hallo==0) goto out;
> du_nochwas_drittes();
> x();
> y();
> z();
> out:
> aufraeumen();

Massives Refactoring erforderlich :) Leider ist das nicht wirklich ein 
Code aus dem wahren Leben, sondern zusammengestöpselter wirrer Kram. 
Dass man da nichts machen kann ist klar.
Nachtrag: Das ist einer der besten Beispiele für Spagetticode und eines 
der schlechtesten Beispiele für guten Code, die ich je gesehen hab :)

Thomas schrieb:
> Gerade im Microcontrollerbereich ist die ROM-Größe oft limitiert.
> Wenn es dann zu Ketten kommt, wie im Beispiel von Michael beschrieben,
> sammelt sich durch Fehlerhandling schnell einiger Code an.
>
> Wer schon in schwierigen Situation war, am Ende des Projekts zu wenig
> ROM-Platz zu haben,kennt die Aktionen, die dann gestartet werden um das
> Projekt zu retten. Strukturierte Programmierung ohne Gotos bleibt dann
> mit als erstes auf der Strecke, wenn bereits zuvor vernünftig
> (platzsparend) progranmmiert wurde.
>
> Nachteil ist natürlich der höhere Aufwand durch schwierigeres Testen.
> Wenn allerdings der Compiler (bei uns Keil-C) in einer höheren
> Optimierungsstufe betrieben wird, werden solche Aktionen teilweise auch
> vom Compiler eingefügt.
>
> Aus meiner Sicht ist an derartigen Anpassungen nichts zu meckern, bei
> uns in der Firma ist es nur leider so, dass dieser Code unverändert
> immer wieder übernommen wird, auch wenn es keine Platzprobleme mehr
> gibt. Hier sollte man sich Gedanken machen, wie dies Optimierungen
> später einfach lokalisiert und rückgebaut werden können.

Ja, leider kann ich das so Unterschreiben. Manchmal ist es einfach so, 
dass man nicht den nächst größeren oder gar einen anderen Controller 
nehmen kann. Besonders, wenn einem fertigen Gerät immer weitere Features 
hinzugefügt werden. Da die Hardware zu ändern kann mal schnell teuer 
werden (FCC, Etsi Neuzulassungen). Das dass aber die Ausnahme sein muss 
und nicht der Standard, schreibest du ja schon selber.

Grüße,

von nicht"Gast" (Gast)


Lesenswert?

Michael Reinelt schrieb:
> 2* Cleanup() ge-inlined :-(

Du weist aber schon, dass deine Vorlage deutlich mehr Cleanups 
beinhaltet

Michael Reinelt schrieb:
> nun kommt die lästige Fehlerbehandlung:tu_was();
> if (!ok) {
>    cleanup();
>    return -E_BE_HAPPY;
> }
> tu_nochwas();
> if (!ok) {
>    cleanup();
>    return -E_DONT_WORRY;
> }
> tu_nochwas_drittes();
> if (!ok) {
>    cleanup();
>    return -E_DONT_KNOW;
> }
> cleanup();
> return 0;

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

nicht"Gast" schrieb:
> Leider ist das nicht wirklich ein
> Code aus dem wahren Leben, sondern zusammengestöpselter wirrer Kram.

Da hast du recht. ich hatte aber gehofft do könntest etwas besser 
abstrahieren...

nicht ganz so wirr, aber auch aus dem Zusammenhang gerissen:
[c]
        irqe.dest_id = entry->fields.dest_id;
        irqe.vector = entry->fields.vector;
        irqe.dest_mode = entry->fields.dest_mode;
        irqe.trig_mode = entry->fields.trig_mode;
        irqe.delivery_mode = entry->fields.delivery_mode << 8;
        irqe.level = 1;
        irqe.shorthand = 0;
        if (irqe.trig_mode != IOAPIC_EDGE_TRIG)
           goto out;

        spin_lock(&ioapic->lock);
        __kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode);
        spin_unlock(&ioapic->lock);
        if (!vector)
           goto out;

        kvm->arch.vioapic = ioapic;
        kvm_ioapic_reset(ioapic);
        kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
        ioapic->kvm = kvm;
        mutex_lock(&kvm->slots_lock);
        ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, 
pic->base_address,
                                      IOAPIC_MEM_LENGTH, &ioapic->dev);
        mutex_unlock(&kvm->slots_lock);
        if (ret < 0)
           goto out;
[c]

Was ich sagen will: Du hast eine nicht ganz so kurze Sequenz fon 
Operationen (Zuweisungen, Funktionsaufrufe, berechnungen) die im 
normalfall einfach linear von vorne bis hinten durchlaufen werden. Die 
Blöcke kannst du auch nciht wie du oben vorgeschlagen hast, mit || 
zusammenhängen. An bestimmten stellen kann was schief gehen (ist aber 
die Ausnahme), und da bietet sich ein goto als "Ausstieg" an.

Für mich (und ich bin hier nicht alleine) viel besser lesbar als tiefe 
if() verschachtelungen.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

nicht"Gast" schrieb:
> Du weist aber schon, dass deine Vorlage deutlich mehr Cleanups
> beinhaltet

Und wenn du mein kommentar dazu gelesen hättest, wüsstest du dass ich 
das absichtlich gemacht habe, um zu zeigen welche nachteile diese 
Konstellation hat :-(

von nicht"Gast" (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Und wenn du mein kommentar dazu gelesen hättest, wüsstest du dass ich
> das absichtlich gemacht habe, um zu zeigen welche nachteile diese
> Konstellation hat :-(

ja, da hast du recht. Bei der ersten Antwort hatte ich es noch gelesen. 
Bei der zweiten .. na ja, shame on me :)

Michael Reinelt schrieb:
> Da hast du recht. ich hatte aber gehofft do könntest etwas besser
> abstrahieren...

Also DAS zu abstrahieren ist echt ne Herausforderung. Da scheitern 
sicher auch Leute mit mehr Grips als ich dann.

Dein Code aus dem zweiten Post ist auch nicht der Renner.

Du scheinst zu viele Sachen in deine Funktion zu stecken. Ohne den Rest 
zu kennen: Teil das Ganze in kleinere Blöcke auf und du wirst sehen, 
dass das Ergebnis deutlich lesbarer als die Gotos sind.

Bsp: statt dem ersten Block
1
 if (entry->fields.trig_mode == IOAPIC_EDGE_TRIG )
2
 {
3
     // copiere das struct in einer funktion
4
     // tu den anderen kram, für den das struct gar nicht benötigt wird
5
 }

Wenn du mehrere trigger modes hast, pack das lieber in ein switch, dass 
dann Funktionen aufruft. Das ist um Welten übersichtlicher, als das, was 
du gepostet hast.

Grüße,

von Yalu X. (yalu) (Moderator)


Lesenswert?

Ich möchte hier noch eine andere Möglichkeit zur Diskussion stellen,
Initialisierungssequenzen mit Ausstiegspunkten ohne explizite Gotos und
verschachtelte Ifs in C zu realisieren. In folgendem Beispiel wird
angenommen, dass die drei Init-Funktionen im Fehlerfall einen von 0
verschiedenen Fehlercode liefern. Jeder Fail landet automatisch an der
dem BLOCK_END folgenden Anweisung.
1
#define BLOCK_BEGIN do {
2
#define BLOCK_END } while(0)
3
#define FAIL_IF(x) if(x) break
4
5
6
int main(void){
7
8
  BLOCK_BEGIN
9
10
    FAIL_IF( init1() );
11
12
    FAIL_IF( init2() );
13
14
    int n = some_computation();
15
16
    FAIL_IF( n < 0 || n > 9 );
17
18
    FAIL_IF( init3(n) );
19
20
    do_main_work();
21
22
  BLOCK_END;
23
24
  cleanup();
25
26
  return 0;
27
}

von Arc N. (arc)


Lesenswert?

Mal an die Theoretiker und Praktiker hier:
Der diesjährige ICFPC startet in ein paar Minuten. Viel Spaß mit und 
ohne goto :)
http://icfpcontest.org/

von emp (Gast)


Lesenswert?

Also das for-"Problem" lässt sich auf mehre Weisen lösen:

1. jede Schleife kann mehrere Abbruchbedingungen haben:
1
bool error = false;
2
3
for(int i = 0; i < 100 && !error;i++)
4
    for(int j = 0; j < 100 && !error;j++)
5
        for(int k = 0; k < 100 && !error;k++)
6
            if(irgendwas)
7
                error = true;

Wenn man nach dem Abbruch wieder vor die Schleifen springen muss:
1
bool error = false;
2
3
do
4
{
5
    for(int i = 0; i < 100 && !error;i++)
6
        for(int j = 0; j < 100 && !error;j++)
7
            for(int k = 0; k < 100 && !error;k++)
8
                if(irgendwas)
9
                    error = true;
10
}
11
while(error);

1. Ja, manchmal habe ich das Gefühl, nur 20 Menschen auf diesem Planeten 
kennen noch eine do-while-Schleife...

2. Bitte im echten Code jede Schleife mit {} versehen, sonst sieht man 
bei solchem Code auch ohne goto nicht mehr durch.

Da ich persönlich for-Schleifen mit mehreren Bedienungen nicht mag, da 
man damit einfach nicht rechnet, würde ich die drei for-Schleifen in 
while Schleifen verwandeln
1
int i = 0;
2
while(i < 100 && error)
3
{
4
    //Zweite Schleife hier hin...
5
6
    i++;
7
}

Um nochmal zum Originalthema zurückzukommen. Ich kenne auch sinnvolle 
goto's. Ein Beispiel ist eine Art try catch nachzubauen:
1
void function()
2
{
3
    if(irengendwasKritisches() == false)
4
        goto error:
5
    if(irengendwasKritisches2() == false)
6
        goto error:
7
    if(irengendwasKritisches3() == false)
8
        goto error:
9
10
    goto end;
11
12
    error:
13
14
    //Fehlerbehandlung, die immer gleich ist, sonst aber in jede if-Anweisung rein müsste.
15
16
17
    end:
18
}

Schönes Wochenende

von emp (Gast)


Lesenswert?

Ich war whol richtig langsam beim beantworten. Yalu X meint hier wohl 
das gleiche wie ich.

von Prog R. (daniel_v)


Lesenswert?

emp schrieb:
>
1
> 
2
> void function()
3
> {
4
>     if(irengendwasKritisches() == false)
5
>         goto error:
6
>     if(irengendwasKritisches2() == false)
7
>         goto error:
8
>     if(irengendwasKritisches3() == false)
9
>         goto error:
10
> 
11
>     goto end;
12
> 
13
>     error:
14
> 
15
>     //Fehlerbehandlung, die immer gleich ist, sonst aber in jede 
16
> if-Anweisung rein müsste.
17
> 
18
> 
19
>     end:
20
> }
21
> 
22
>
>
> Schönes Wochenende

Die Variante mit den For-Schleifen finde ich toll, das hab ich so noch 
nie gesehen.

Was das letzte Beispiel angeht: Da kannst du auch gleich eine Funktion 
MyErrorHandler(ERR_TYPE) aufrufen und hast sogar eine Unterscheidung 
dabei. Mit nahezu gleichem Codeaufwand wie beim GOTO.

Daniel

: Bearbeitet durch User
von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Yalu X. schrieb:
> #define BLOCK_BEGIN do {
> #define BLOCK_END } while(0)
> #define FAIL_IF(x) if(x) break

Ich bin versucht zu sagen "real programmers don't use Pascal", aber ich 
verkneifs mir mal ;-)

Grundsätzlich natürlich eine Möglichkeit, nur: warum so viel Aufwand, 
nur um ein goto zu tarnen?

nicht"Gast" schrieb:

> Dein Code aus dem zweiten Post ist auch nicht der Renner.

ist nicht mein Code :-)

> Du scheinst zu viele Sachen in deine Funktion zu stecken. Ohne den Rest
> zu kennen: Teil das Ganze in kleinere Blöcke auf und du wirst sehen,
> dass das Ergebnis deutlich lesbarer als die Gotos sind.

nein, werde ich nicht. und das ist nicht mal unbedingt meine Meinung.

Der Code wurde recht wahllos aus den aktuellen Linux-Sourcen rauskopiert 
(irgendwas im KVM-Bereich)

Ohne jetzt einen Glaubenskrieg anzetteln zu wollen: Ich hab in meinem 
Leben sehr viel Code gelesen, viel guten Code, ein paar echte "perlen", 
und leider bei weitem zu viel schlechten Code. Für mich zählt der 
Linux-Kernel-Source auf jeden Fall zu den positiven Beispielen. Der Code 
ist gut, effizient, leistungsfähig, und durch viele Hände gegangen, und 
wurde von sehr vielen Augen gelesen. Goto ist dort alles andere als 
verboten, wird aber mit Bedacht eingesetzt.

Du kannst ja mal versuchen, dort zu predigen, wie du das alles viel 
besser machen würdest. Gib mir aber bitte vorher Bescheid, den Thread 
möchte ich nicht verpassen :-)

Ums nochmal auf den Punkt zu bringen: Goto hat absolut seine 
Berechtigung in gewissen Fällen: kritischer Code, kleiner 
(Cache-)Footprint, Rücksicht auf die Pipeline sind ein paar davon. Ein 
guter Programmierer kennt das, weiß das zu schätzen und kann einschätzen 
wann ein goto angebracht ist und wann nicht. Das reflexartige "goto ist 
böse" deutet nur auf eins hin: Die Aussage kommt nicht von einem 
guten, erfahrenen Programmierer.

von Klaus Kaiser (Gast)


Lesenswert?

Ich schicke den Link nochmal. Hat offensichtlich keiner gelesen. Wer 
mag, der kann sich auch die ganze Diskussion durchlesen, aber der 
verlinkte Post reicht eigentlich.

http://programmers.stackexchange.com/questions/154974/is-this-a-decent-use-case-for-goto-in-c/154980#154980

Now stop this :)

von Matthias L. (Gast)


Lesenswert?

>Da ich persönlich for-Schleifen mit mehreren Bedienungen nicht mag

Wie sieht so eine Bedienung einer for-Schleife aus? Start-Stopp-Abbruch?

;-)

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Klaus Kaiser schrieb:
> 
http://programmers.stackexchange.com/questions/154974/is-this-a-decent-use-case-for-goto-in-c/154980#154980

Schön, danke! Trifft genau das was ich versuche zu vermitteln.

<duckundwegrenn>
nur müssten das die Mädels hier verstehen wollen...
</duckundwegrenn>

von W.S. (Gast)


Lesenswert?

nicht"Gast" schrieb:
> Sollte der Compiler nicht bei dir auch meckern?

Nein. Er erkennt nämlich direkt zuvor den unbedingten Sprung und weiß 
dann, daß das Ende unerreichbar ist.

Ich hab aber aus Klaus Kaisers Link ne Sache, die mir durchaus sinnvoll 
erscheint, obwohl sie etwas störrisch aussieht:

...
 if (Procedure_A()==fail) goto undo_A;
 if (Procedure_B()==fail) goto undo_B;
 if (Procedure_C()==fail) goto undo_C;
...
 return OK;

 undo_C:
   Undo_Procedure_C();
 undo_B:
   Undo_Procedure_B();
 undo_A:
   Undo_Procedure_A();
 return Failed;

De Knackpunkt ist hierbei das korrekte Zurückrollen von den Dingen, die 
bereits angerichtet sind. Man versuche das mal stringenter auszudrücken.

W.S.

von MCUA (Gast)


Lesenswert?

>Ums nochmal auf den Punkt zu bringen:
oder anders gesagt, reine Geschacksache, was 'besser' lesbar ist.
Und einem Compiler sollte es sowiso egal sein, welche 'switches' er 
vorfindet.
Goto in ASM stiftet nur Verwirrung, weil es dort sinngemäss JMP heissen 
müsste.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

MCUA schrieb:
> oder anders gesagt, reine Geschacksache, was 'besser' lesbar ist.

W.S. schrieb:
> Man versuche das mal stringenter auszudrücken.

Jein

ich behaupte, goto macht den Code oft schlechter lesbar, (oft für 
"eingeweihte" durchaus auch besser)

Es geht aber nicht nur um die Lesbarkeit, sondern meist darum, dem 
Compiler zu erlauben, kompakten, effizienten und damit optimalen Code zu 
erzeugen.

In manchen Bereichen (OS Kernel, embedded mit "engen" bedingungen) ist 
das notwendig. ich weiss schon, "... the root of all evil", aber das 
obige Konstrukt von W.S. ist es wert, es sich anzugewöhnen. Es ist 
straight, sauber, optimal, schön.

(Leider wird man damit in der Ausbildung/Uni vermutlich Probleme 
bekommen. Liegt aber IMHO daran, dass Ausbildner selten viel 
Programmiererfahrung haben, eher Theoretiker sind. und in der Theorie 
gibts ja keinen Unterschied zwischen Theorie und Praxis, aber in der 
Praxis sehr wohl)

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

MCUA schrieb:
> Goto in ASM stiftet nur Verwirrung, weil es dort sinngemäss JMP heissen
> müsste
Wieso, es ist doch egal ob man zur Zieladresse hingeht oder springt...
Wenn sich der Hersteller für eines der beiden oder vllt. noch ein 
anderes  Mnemonic entschieden hat dann ist es ganz eindeutig was 
GOTO/JMP für diesen Prozessortyp bedeutet.

von foo (Gast)


Lesenswert?

Yalu X. schrieb:
> Ich möchte hier noch eine andere Möglichkeit zur Diskussion stellen

Von Sprache neu definieren mittels Präprozessor halt ich gar nichts.
Warum nicht dein Konstrukt so lassen, aber mit do, if und break.

von MCUA (Gast)


Lesenswert?

>Es geht aber nicht nur um die Lesbarkeit, sondern meist darum, dem
>Compiler zu erlauben, kompakten, effizienten und damit optimalen Code zu
>erzeugen.
Den Compiler hat das nicht zu jucken.
Ansonst bleibt es dabei, es ist Geschmacksache (sagt der Andere und 
beisst in die Seife).

>Wieso, es ist doch egal ob man zur Zieladresse hingeht oder springt...
natürlich ist es wurscht, aber kein Mensch (ausser die von PIC) 
verwenden für JMP Goto in ASM. Warum der Quatsch? (doch nicht um mit 
'goto' ein Hochsprachenkonstrukt im ASM zu assoziiren) (allerd. ist bei 
PIC (aus Urzeiten) syntakt. vieles anders).

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

MCUA schrieb:
> Den Compiler hat das nicht zu jucken.

Leider sind wir noch nicht im Jahr 2525. Heute macht der Compiler noch 
was du tippst, und nicht was du willst.

von nicht"Gast" (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Der Code wurde recht wahllos aus den aktuellen Linux-Sourcen rauskopiert
> (irgendwas im KVM-Bereich)

Da hast du mich aber erwischt. Trozdem bleibt das Stück Code scheiße. Es 
fehlt einfach der Kontext um das beurteilen zu können. Wenn du die 
gesamte Funktion gepostet hättest, würde das sicher anders aussehen, 
aber so bleibt es unzusammenhängendes Geschwurbel.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

nicht"Gast" schrieb:
> Trozdem bleibt das Stück Code scheiße.
Watch your language!

> Es
> fehlt einfach der Kontext um das beurteilen zu können. Wenn du die
> gesamte Funktion gepostet hättest, würde das sicher anders aussehen,
> aber so bleibt es unzusammenhängendes Geschwurbel.

www.kernel.org

Ich sprech dir jetzt einfach mal die Kompetenz ab, das zu beurteilen. 
Vermutlich ist es besser du schreibst weiter deine tic-tac-toe programme 
ohne goto's ...

<sorry>

: Bearbeitet durch User
von Meister E. (edson)


Lesenswert?

MCUA schrieb:
> natürlich ist es wurscht, aber kein Mensch (ausser die von PIC)
> verwenden für JMP Goto in ASM. Warum der Quatsch? (doch nicht um mit
> 'goto' ein Hochsprachenkonstrukt im ASM zu assoziiren) (allerd. ist bei
> PIC (aus Urzeiten) syntakt. vieles anders).

Quatsch ist, sich darüber aufzuregen. Ich glaube nicht, dass alle 
Hersteller verpflichtet sind, die Nomenklatur von Intel zu übernehmen.

von Gaestchen (Gast)


Lesenswert?

Walter Tarpan schrieb:
> if (status!=0)
>     goto error;
>
>   return status; // = 0
>
>   error:
>   I2C_reset(EEPROM_I2C_DEVICE);
>   return status;

Ein hervorragendes Beispiel für die verwendung eines Goto.

Könntest du aber noch deutlich verbessern:
  goto unten
  oben:
  goto abfrage
  fallja:
  goto entwederoderdochnicht
  abfrage:
  goto fallja
  alsodochdoch:
  if (status!=0)
    goto error;
  goto noerror
  error:
  I2C_reset(EEPROM_I2C_DEVICE);
  return status;
  noerror:
  return status; // = 0
  entwederoderdochnicht:
  goto alsodochdoch
  unten:
  goto oben



BTW genau soetwas ist der Grund warum es für Anfänger verboten ist goto 
zu verwenden. Weil dann so ein Mist entsteht und sie es sich angewöhnen, 
... oder es sogar noch als sinvolles Beispiel posten. Nirgendwo war es 
überflüssiger als in diesem Beispiel.

von Bastler (Gast)


Lesenswert?

Sollte man nicht alle anderen Statements, mit denen man bei genügend 
Anstrengung Schindluder treiben kann, auch verteufeln. Immer nur auf das 
arme GOTO, wie gemein.

Und ist nicht das Beispiel
1
 nestedFor()
2
 {
3
   for (int i=0;i<255;i++)
4
   {
5
     for (int j=0;j<255;j++)
6
     {
7
       for (int k=0;k<255;k++)
8
       {
9
         if (i==100 && j==20 && k==2) return;
10
       }
11
     }
12
   }
13
 }
auch ein simuliertes GOTO. Indirekt, über die zuvor auf dem Stack 
abgelegte Ziel-Adresse.

Schreibt einer, der die Wahl nicht hat, denn die Sprache, in der er seit 
25 Jahren seine Brötchen programmiert, ist GOTG frei. Freizeit Code 
auf'm AVR in C hat aber manchmal ein goto, damit jede Version des 
Compilers sich beim Optimieren an seine Vorgaben hält. Die Welt ist eben 
nicht Schwarz/Weis, sondern hell-/dunkel-grau.

von Konrad S. (maybee)


Lesenswert?

@Karl und @Yalu
Danke für die Erläuterungen.

von Falk B. (falk)


Lesenswert?

Jeder Assembler hat ein GOTO und die diversen mehrfachen return, break 
etc. C-Konstrukte können nur mit GOTO/JUMP in ASM umgesetzt werden.
Jaja, Ein Hochsprachen GOTO ist halt irgendwie gefühlt anders als ein 
ASM GOTO.

von Konrad S. (maybee)


Lesenswert?

Yalu X. schrieb:
>
1
> #define BLOCK_BEGIN do {
2
> #define BLOCK_END } while(0)
3
> #define FAIL_IF(x) if(x) break
4
> 
5
> 
6
> int main(void){
7
> 
8
>   BLOCK_BEGIN
9
> 
10
>     FAIL_IF( init1() );
11
> 
12
>     FAIL_IF( init2() );
13
> 
14
>     int n = some_computation();
15
> 
16
>     FAIL_IF( n < 0 || n > 9 );
17
> 
18
>     FAIL_IF( init3(n) );
19
> 
20
>     do_main_work();
21
> 
22
>   BLOCK_END;
23
> 
24
>   cleanup();
25
> 
26
>   return 0;
27
> }
28
>

Das ist genau der Fall, wo ich die define so abändern würde:
1
#define BLOCK_BEGIN
2
#define BLOCK_END block_end:
3
#define FAIL_IF(x) if(x) goto block_end
Ganz einfach aus dem Grund, weil es dem Wesen nach keine Schleife ist. 
Aber lieber schreibe ich offen und ehrlich das goto hin.

von F. F. (foldi)


Lesenswert?

Zwergenball schrieb:
> BloedeFrage schrieb:
>> Sämtliche Leute die mir bisher programmieren beigebracht haben
>
> Wie viele haben dir das programmieren beigebracht? Welche
> Programmiersprachen hast du dabei erlernt? Haben diese Leute die
> Forderung - goto nicht zu verwenden - begründet? Wie wurde die Forderung
> begründet? Wie alt bist du? Welchen Schulabschluss hast du? Hast du
> einen Hochschulabschluss? Wenn ja, welchen Anschluss hast?

... und wieso bist du so neugierig?

Deine Fragen haben doch nichts mit der eigentlichen Frage zu tun.

von Konrad S. (maybee)


Lesenswert?

W.S. schrieb:
> Ein simples
> Beispiel ist die Grundschleife bei Mikrocontrollern:
> int main (void)
> { initialisiere();
>   immerzu:
>     machedies();
>     machedas();
>     machenochwas();
>   goto immerzu;
> }
> Wenn man das mit einem while(1) formuliert, dann meckern manche
> Compiler, daß main ja gar kein Ergebnis zurückgibt - zu Recht (im
> Prinzip). Also findet man bei solchen Strategen nach der Endlosschleife
> noch ein return 0 oder so, um den schieren Formalismus zu befriedigen.

Compiler-Meckern hin oder her, das hier ist dem Wesen nach eine 
Endlos-Schleife und ein while(1) bringt genau das zum Ausdruck. Hier 
finde ich das goto deshalb fehl am Platz.

von Yalu X. (yalu) (Moderator)


Lesenswert?

foo schrieb:
> Yalu X. schrieb:
>> Ich möchte hier noch eine andere Möglichkeit zur Diskussion stellen
>
> Von Sprache neu definieren mittels Präprozessor halt ich gar nichts.
> Warum nicht dein Konstrukt so lassen, aber mit do, if und break.

Weil das do-while eine Pseudoschleife ist und deswegen Verwirrung
stiften könnte.

Aber ich stimme dir trotzdem zu: Solche Makros, die etwas anderes
definieren als Konstanten oder funktionsähnliche Dinge, mag ich
eigentlich auch nicht.

Konrad S. schrieb:
> Das ist genau der Fall, wo ich die define so abändern würde:
>
>  #define BLOCK_BEGIN
>  #define BLOCK_END block_end:
>  #define FAIL_IF(x) if(x) goto block_end
>
> Ganz einfach aus dem Grund, weil es dem Wesen nach keine Schleife ist.
> Aber lieber schreibe ich offen und ehrlich das goto hin.

Die do-while-Schleife habe ich aus drei Gründen verwendet:

1. Man braucht kein Goto-Label. Somit können auch mehrere BLOCK_BEGIN-
   BLOCK_END-Konstrukte nacheinander in einer Funktion verwendet werden,
   ohne dass es Konflikte mit Labels gleichen Namens gibt.

2. Mehrere BLOCK_BEGIN-BLOCK_END-Konstrukte nacheinander werden selten
   benötigt. Manchmal möchte man sie aber verschachteln können, bspw. in
   solchen Fällen:

   Klaus Kaiser schrieb:
     http://programmers.stackexchange.com/questions/154974/is-this-a-decent-use-case-for-goto-in-c/154980#154980

   Dank der verwendeten Pseudoschleife geht das problemlos, und der
   Compiler kontrolliert dabei die korrekte Verschachtelung.

3. Die Definition von BLOCK_BEGIN und BLOCK_END als Schleife verhindert,
   dass sie unsinnig platziert werden, bspw. in unterschiedlichen
   Blöcken, in der falschen Reihenfolge (BLOCK_END vor dem BLOCK_BEGIN)
   oder in anderen spaghettiverdächtigen Anordnungen. Deren Verwendung
   wird damit deutlich eingeschränkt und erlaubt es dem Compiler, einige
   Fehler zu erkennen, die bei der Verwendung von Goto unentdeckt
   blieben.

Zugegebenermaßen benutze ich diese Makros selber auch nicht, da auch die
sorgfältige Verwendung von Gotos normalerweise nicht zu Problemen führt.
Ich habe sie mir nur für solche Leute ausgedacht, denen die direkte
Verwendung von Gotos in zur Fehlerbehandlung zweifelhaft erscheint und
die – durchaus nachvollziehbar – einen Break dem Goto vorziehen.

von Konrad S. (maybee)


Lesenswert?

Yalu X. schrieb:
> Zugegebenermaßen benutze ich diese Makros selber auch nicht, da auch die
> sorgfältige Verwendung von Gotos normalerweise nicht zu Problemen führt.

Eben! Und wer kein goto mag und ohne auskommt, der darf auch glücklich 
werden. ;-)

von Arc N. (arc)


Lesenswert?

W.S. schrieb:
> Ich hab aber aus Klaus Kaisers Link ne Sache, die mir durchaus sinnvoll
> erscheint, obwohl sie etwas störrisch aussieht:
>
> ...
>  if (Procedure_A()==fail) goto undo_A;
>  if (Procedure_B()==fail) goto undo_B;
>  if (Procedure_C()==fail) goto undo_C;
> ...
>  return OK;
>
>  undo_C:
>    Undo_Procedure_C();
>  undo_B:
>    Undo_Procedure_B();
>  undo_A:
>    Undo_Procedure_A();
>  return Failed;
>
> De Knackpunkt ist hierbei das korrekte Zurückrollen von den Dingen, die
> bereits angerichtet sind. Man versuche das mal stringenter auszudrücken.
1
if (procA() != fail) {
2
   if (procB() != fail) {
3
      if (procC() != fail) {
4
         return OK;
5
      }
6
      undoC();
7
   }
8
   undoB();
9
}
10
undoA();
11
return failed;

von nicht"Gast" (Gast)


Lesenswert?

Sanfte Grüße,

Michael Reinelt schrieb:
> nicht"Gast" schrieb:
>> Trozdem bleibt das Stück Code scheiße.
> Watch your language!

Vielen Dank für die Korrektur meiner inneren Einstellung. :)

Ich hab mir mal deine Vorwürfe zu Herzen genommen und mir die aktuellen 
Sourcen heruntergeladen. Ich bin mir nicht sicher, ob ich die richtige 
Funktion gefunden hab, deswegen poste ich sie mal hier. Allerdings 
taucht in ihr das einzige mal im gesamten Source das struct irqe auf.
1
static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
2
{
3
  union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
4
  struct kvm_lapic_irq irqe;
5
  int ret;
6
7
  if (entry->fields.mask)
8
    return -1;
9
10
  ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
11
         "vector=%x trig_mode=%x\n",
12
         entry->fields.dest_id, entry->fields.dest_mode,
13
         entry->fields.delivery_mode, entry->fields.vector,
14
         entry->fields.trig_mode);
15
16
  irqe.dest_id = entry->fields.dest_id;
17
  irqe.vector = entry->fields.vector;
18
  irqe.dest_mode = entry->fields.dest_mode;
19
  irqe.trig_mode = entry->fields.trig_mode;
20
  irqe.delivery_mode = entry->fields.delivery_mode << 8;
21
  irqe.level = 1;
22
  irqe.shorthand = 0;
23
24
  if (irqe.trig_mode == IOAPIC_EDGE_TRIG)
25
    ioapic->irr &= ~(1 << irq);
26
27
  if (irq == RTC_GSI && line_status) {
28
    /*
29
     * pending_eoi cannot ever become negative (see
30
     * rtc_status_pending_eoi_check_valid) and the caller
31
     * ensures that it is only called if it is >= zero, namely
32
     * if rtc_irq_check_coalesced returns false).
33
     */
34
    BUG_ON(ioapic->rtc_status.pending_eoi != 0);
35
    ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe,
36
        ioapic->rtc_status.dest_map);
37
    ioapic->rtc_status.pending_eoi = (ret < 0 ? 0 : ret);
38
  } else
39
    ret = kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe, NULL);
40
41
  if (ret && irqe.trig_mode == IOAPIC_LEVEL_TRIG)
42
    entry->fields.remote_irr = 1;
43
44
  return ret;
45
}

Wenn ich die Richtige erwischt hab, scheint da wohl doch einer ein 
Refactoring betrieben zu haben und hat die Gotos rausgeschmissen.

In anderen Funktionen in dieser Datei (ioapic.c) gibs natürlich auch 
noch Gotos. Aber es scheint schon einen gewissen Trend zu geben.

Deine Beurteilung über meine Qualifikation tangiert mich damit auch 
nicht mehr wirklich.
An dieser Stelle sei gesagt: Der absolut überwiegende Teil der 
Kernelentwickler lässt mich mit Sicherheit wie ein Baby aussehen. Daran 
gibts kein Zweifel.

****
Ich hab übrigens in einem anderen Post schon geschrieben, dass es 
durchaus Situation gibt (ja, hatte ich auch schon selber), in denen Goto 
seinen Sinn hat.

Ich glaub, ich muss mal meine Einstellung klarstellen :)

Bei meinen Coding geht es immer um:
 - Lesbarkeit
 - Wartbarkeit
 - Wiederverwendbarkeit

Die Fehlerfreiheit überragt natürlich alles ^^.

Ich behaupte auch an der Stelle nicht, dass ich so gut bin, dass ich es 
immer hinbekomme.
Ich hab schon nach 2 Wochen schon mal ein halbes Programm umstricken 
müssen, weil ich es nicht mehr verstanden habe.

Da ich performance unkritische Sachen entwickle, steht das auch gar 
nicht auf meiner Agenda. Manchmal musste ich allerdings auch schon in 
einige Richtungen optimieren, weil zum Beispiel auf einmal der 
Speicherverbrauch epxlodiert ist.

Die Beispiele mit Goto hier im Thread bedeuten für mich bisher immer 
eine schlechtere Lesbarkeit weil sie unnötig einen Bruch im Code 
darstellen. Geschweifte Klammern zeigen immer schön Start und Ende eines 
Scopes an.
Sprungziele von gotos können überall sein und man muss sie erst suchen.

Was ich meine:
1
...
2
 if (Procedure_A()==fail) goto undo_A;
3
 if (Procedure_B()==fail) goto undo_B;
4
 if (Procedure_C()==fail) goto undo_C;
5
...
6
 return OK;
7
8
 undo_C:
9
   Undo_Procedure_C();
10
 undo_B:
11
   Undo_Procedure_B();
12
 undo_A:
13
   Undo_Procedure_A();
14
 return Failed;

warum kann ich meine Funktion nicht so stricken, dass Undo_Procedure_C() 
direkt ausgeführt wird wo's fehlschlägt? Dann seh ich sofort, was 
passiert. So muss ich erst zum Goto Ziel (vielleicht noch scollen).
btw. ist das wirklich gut, dass im Fehlerfall der Undo Code von allen 
drei Methoden ausgeführt wird?

An der Stelle nicht vergessen. Goto kann vorkommen. Ist ja nicht umsonst 
in den meisten Sprachen integriert. Der Ottonormal 
Durchschnittsprogrammierer tut sich jedoch in dem meisten Fällen eher 
schlecht damit und sollte seinen Code lieber so strukturieren, dass er 
es nicht braucht.
Damit meine ich nicht die kleinen Beispiele hier, sondern das fängt 
schon eine Ebene weite höher im Funktionsaufbau an. Überwiegend kommt 
dabei besser lesbarer Code raus.

Wenn die Lesbarkeit aus zwingenden Gründen leiden muss um sein Ziel zu 
erreichenm, dann soll es so sein. Vermeiden sollte man das aber in 
standard Situationen.


Das auch Profis mit Goto manchmal nicht umgehen können zeigt ja Apple 
sehr schön :)

https://gotofail.com/faq.html

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

nicht"Gast" schrieb:
> Wenn ich die Richtige erwischt hab, scheint da wohl doch einer ein
> Refactoring betrieben zu haben und hat die Gotos rausgeschmissen.

Es ist der falsche Code. Der von mir zitierte war irgendwo aus dem 
Bereich kvm. und er war aktuell (2.6.15)

Aber - bevor du weitersuchst: der tatsächliche Code tut absolut nichts 
zur sache! ich wollte damit nur illustrieren, das es nicht immer so 
einfach ist wie in den hier gebrachten Beispielen, proc_a() ist eben 
nicht nur eine zeile, sondern das können auch viele sein. (Und auf 
deinen Vorposter geh ich deshalb erst gar nicht mehr ein - ich 
kapituliere)

nicht"Gast" schrieb:
> Deine Beurteilung über meine Qualifikation tangiert mich damit auch
> nicht mehr wirklich.

War auch weder ernst noch persönlich gemeint - lassen wirs gut sein?

nicht"Gast" schrieb:
> Die Beispiele mit Goto hier im Thread bedeuten für mich bisher immer
> eine schlechtere Lesbarkeit weil sie unnötig einen Bruch im Code
> darstellen. Geschweifte Klammern zeigen immer schön Start und Ende eines
> Scopes an.
> Sprungziele von gotos können überall sein und man muss sie erst suchen.

Siehst du, ich seh's genau gegenteilig: Das Schöne am Goto ist, dass das 
Sprungziel da steht, und ich schnell danach suchen kann; während ich 
beim break erst (mühsam) das Ende des Scopes suchen muss. und von der 
anderen seite her: wenn ich ein Label sehe, weiss ich dass es 
(vermutlich) angesprungen wird - was ich bei einer geschlossenen 
geschwungenen Klammer erstmal nicht erkennen kann.

nicht"Gast" schrieb:
> warum kann ich meine Funktion nicht so stricken, dass Undo_Procedure_C()
> direkt ausgeführt wird wo's fehlschlägt?

Nochmal: weil ich Code nicht duplizieren will. und selbst wenn ich so 
klug bin, undo_procedure_c() in eine Funktion auszulagern (was in den 
wenigsten Fällen Sinn macht, weil ich gefühlte tausend parameter 
übergeben müsste) kommt der Compiler (mein Freund und Helfer) und 
dupliziert den Code, weil er den aufruf inline macht. Das will ich 
nicht, weil es meinen Cache-Footprint unnötig erhöht.

Ich bin ja auch keineswegs der Meinung, man sollte goto verwenden. 
keinesfalls! ich selbst verwende es eher selten.

Was ich aber nicht ausstehen kann, ist das "goto ist böse", und das 
sofortige "Der Code ist scheisse, weil ein goto drinnen ist". Das zeigt 
nur eines - derjenige hat es nicht verstanden.

Und was ich beängstigend finde - dass obiges offensichtlich gelehrt 
wird.

Und wie sich hier in diesem Thread wieder zeigt - so viele fühlen sich 
berufen, zu erklären wie man's besser machen sollte. Und keiner 
versteht, dass er (in bestimmten Fällen) einfach falsch liegt. Keiner 
liest Klaus Kaisers Link, und wenn er gelesen wird, wird er nicht 
verstanden.

Traurige Programmierer-Welt :-(

: Bearbeitet durch User
von nicht"Gast" (Gast)


Lesenswert?

Michael Reinelt schrieb:
> War auch weder ernst noch persönlich gemeint - lassen wirs gut sein?

Gerne (Handshake)

Im Grunde reden wir ja mit fast der gleichen Meinung aneinander vorbei 
:)


Eigentlich finde ich es ganz gut, dass es nicht gelehrt wird. Anfänger 
werden durch so was zu schlechten Code verleitet (Ich hoffe das 
bestreitest du nicht :).

Wenn man wirklich mal an den Punkt kommt, an dem man es nicht vermeiden 
kann, ist man meistens auch so weit, dass man es vernünftig benutzen 
kann.

Übrigens ein 'grep -Ro "goto" | wc -l' über den aktuellen Source 
(3.15.6) ergibt die Zahl 117157. Das ist mal krass.

Grüße,

von keinLichtAufGing (Gast)


Lesenswert?

Inzwischen scheint der TO vom Thread plattgewalzt worden zu sein.
Um aber nochmal auf die Ursprungsfrage nachdem "warum" zu kommen,
sind mir folgende mehr oder weniger historische Begründungen
bekannt (gemacht) worden:

1. Das menschliche Gehirn verarbeitet tendenziell Strukturen
   besser als zeitliche Abfolgen. Ein Programm, das nur aus
   If/While/Abfolgen und Prozeduraufrufen besteht, ist quasi
   statisch ("diese Schleife schneidet die Verzeichnisse von den
   Pfadnamen ab, diese Prozedur..."). Den Gegenpol dazu bildet
   ein rein goto-basiertes 'lineares' Programm, dessen zeitlicher
   Ablauf nachvollzogen werden muss, um es zu verstehen.
     Beispiel aus dem Alltag wäre ein Tankwart, der einem Touristen
   auf der Karte zeigt: "Sie sind hier und wollen nach da" vs.
   ohne Karte: "Sie fahren die X-Strasse entlang, bei der dritten
   Ampel rechts, dann bis zum Y-Ring, folgen dem bis zu ..."
   (zehn weitere Stationen - Tourist hat längst den Faden
   verloren).

2. Das goto-Verbot wurde aufgestellt, als die Software-Krise zum
   erstenmal bewusst wahrgenommen wurde. Da kam die Forderung auf,
   Programme sollten so einfach und modularisiert wie möglich
   sein. Goto galt als das Mittel, um Programmteile zu einem
   undurchdringlichen Monolithen zu verbinden ("big ball of mud").

3. Parallel zur Software-Krise gab es eine Hype-Phase für die
   'formale Verifikation', also den Wunsch, Korrektheit von
   Software mathematisch zu beweisen. Die strukturierte
   Programmierung kam der vielfach verwendeten Hoare-Logik und
   dem Floyd-Invariantenverfahren sehr entgegen, während goto
   die Kalküle schnell an ihre Grenzen brachte - umso mehr, als
   man damals noch im wesentlichen mit Zettel und Stift bewies.
     Dieses Argument sticht heute kaum noch, vor allem weil die
   Verifikationstechnik sich als i.a. wirtschaftlich unrentabel
   herausstellte.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

nicht"Gast" schrieb:
> Eigentlich finde ich es ganz gut, dass es nicht gelehrt wird.
Mißverständnis: ich bin nicht dafür dass goto gelehrt wird, aber ich 
verwehre mich gegen die Lehre "goto => böse"

> Anfänger
> werden durch so was zu schlechten Code verleitet (Ich hoffe das
> bestreitest du nicht :).
Nö :-)

nicht"Gast" schrieb:
> Übrigens ein 'grep -Ro "goto" | wc -l' über den aktuellen Source
> (3.15.6) ergibt die Zahl 117157. Das ist mal krass.

Du findest das krass. Ich nicht ;-)

von MCUA (Gast)


Lesenswert?

>> natürlich ist es wurscht, aber kein Mensch (ausser die von PIC)
>> verwenden für JMP Goto in ASM. Warum der Quatsch? (doch nicht um mit
>> 'goto' ein Hochsprachenkonstrukt im ASM zu assoziiren) (allerd. ist bei
>> PIC (aus Urzeiten) syntakt. vieles anders).
>Quatsch ist, sich darüber aufzuregen. Ich glaube nicht, dass alle
>Hersteller verpflichtet sind, die Nomenklatur von Intel zu übernehmen.
Aber warum (nur bei PICs) Gotu in ASM , wo es doch (verteufelterweise) 
in Hochsprachen benutzt wird?

von Sven B. (scummos)


Lesenswert?

In C macht goto Sinn, weil es oft keine andere vernünftige Möglichkeit 
gibt, Resourcen wieder freizugeben. Deshalb ist das auch im Linux-Kernel 
so viel vorhanden und dort auch ok. In C++ möchte ich aber mal ein 
Beispiel sehen, wo es sinnvoll ist goto zu benutzen.
Die letzten fünf gotos die ich in C++-Code gefunden habe konnte man 
durch ein kürzeres und übersichtlicheres nicht-goto-Konstrukt ersetzen.

: Bearbeitet durch User
von Max H. (hartl192)


Lesenswert?

MCUA schrieb:
> Aber warum (nur bei PICs) Gotu in ASM
Der PIC Assembler kennt den "Gotu" Befehl nicht mal...

: Bearbeitet durch User
von dotm (Gast)


Lesenswert?

Ich verwende auch goto zum deinitialisieren meiner Funktionen.
Hab bis jetzt noch keine elegantere Lösung gefunden. Siehe auch:
Beitrag "C: Fehlerbehandlung und -weiterleitung"

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.