C-Programm ohne goto

Gast #1896587
Lesenswert?

Schönen guten Abend

Ich habe eine kleines C-Programm
1
for (Schleifenbedingung)
2
   {
3
    Befehl;
4
    Befehl;
5
    while (Bedingung)
6
       {
7
        Befehl;
8
        if (Abfrage) break; //verlasse beide Schleifen
9
        Befehl;
10
       }
11
   }

Wenn „Abfrage“ erfüllt ist, möchte ich nicht
nur die while-Schleife sondern auch sofort die
for-Schleife verlassen. Mit break wird ja jetzt
nur die while-Schleife verlassen.

Gibt es eine Lösung ohne goto ;-) ?
Gast #1896685
Lesenswert?

Wie wärs es in eine Unterfunktion zu packen?
1
void foo(void) {
2
 for (Schleifenbedingung) {
3
  Befehl;
4
  Befehl;
5
  while (Bedingung) {
6
   Befehl;
7
   if (Abfrage) return; //verlasse beide Schleifen
8
   Befehl;
9
  }
10
 }
11
 return;
12
}

Eventuell die Schleifenbedingung, Bedingung und Abfragewert als 
Parameter übergeben falls sie nicht global sind oder lokal gesetzt 
werden.
Gast #1896704
Lesenswert?

Kermit schreibt:
>Warum kein goto?

Goto ist verpönt, da man damit
sehr unübersichtlichen Programmcode
erzeugen kann (Spagetti-Programmierung).
In JAVA gibt es z.B. gar kein goto mehr.

Ich werde aber hier doch ein goto nehmen,
und das Sprungziel direkt unter die Schleifen
setzten. Das scheint mir gut lesbar zu sein.

Danke an alle für die Tipps!
#1896728
Lesenswert?

Grübler schrieb:
> Goto ist verpönt, da man damit
> sehr unübersichtlichen Programmcode
> erzeugen kann (Spagetti-Programmierung).

Kreissägen führen bei unsachgemäßer Verwendung regelmäßig zu schweren 
Verletzungen, dennoch sind sie nicht "verpönt".

Du lieferst selbst das beste Beispiel, warum ein pauschales "goto ist 
böse" schwachsinnig ist.

> In JAVA gibt es z.B. gar kein goto mehr.

Da gibt es aber ein break mit Label, eben weil der Abbruch von 
verschachtelten Schleifen sonst unübersichtlich und fehleranfällig wird 
(Pascal lässt grüßen...).

Wenn man es drauf anlegt kann man damit genauso üblen Code produzieren 
wie mit goto in C. Eigentlich sogar noch übler, da das Label bei diesen 
Konstrukten dann nichtmal an der Stelle steht, wo wirklich hingesprungen 
wird. Es steht nur nicht das angeblich böse "goto" da.

Andreas
#1896739
Lesenswert?

Wäre es nicht einfacher, die Schleifenbedingung für das For zu erfüllen?

z.B.
1
int i;
2
bool abbruch = false;
3

4
for (i=0; (i<4)&&(!abbruch); i++)
5
{
6
  Befehl();
7
  Befehl();
8
  while (Bedingung)
9
  {
10
    Befehl();
11
    if(Bedingung)
12
    {
13
      abbruch = true;
14
      break;
15
    }
16
   }
17
}

_.-=: MFG :=-._
#1896806
Lesenswert?

Grübler schrieb:
> Gibt es eine Lösung ohne goto ;-) ?

Nein, es gibt keine Lösung, die gleich effektiv ist.

Die mit Return kostet etwas Stack, ist aber gleich gut leserlich, wie 
das Goto. Und dann kommen aber die Nörgler, die sagen, daß jede Funktion 
nur ein Return haben soll.

Die mit ner Variable macht den Code deutlich unleserlicher und kann 
sogar richtig teuer werden, wenn extra für diese zusätzliche Variable 
ein Stackframe angelegt werden muß.


Man sollte Goto nicht unnütz nehmen. Wenn es aber paßt, wie die Faust 
aufs Auge, dann nimmt man es einfach.

Irgendwelche Dogmen auszusprechen und sich sklavisch daran 
festzukrallen, halte ich für Schwachsinn. Der gesunde Menschenverstand 
sollte Vorrang haben.


Ein ähnliches Problem hat man auch bei Switch-Anweisungen in einer 
Schleife.
Sehr oft gibt es einen oder mehrere Case, die die Schleife verlassen. 
Durch die Doppelfunktion des Break ist das aber nicht möglich
Daher findet man Goto auch sehr oft in Switch-Anweisungen.
Sehr sinnvoll wäre daher ein extra Schlüsselwort zum Beenden eines Case 
gewesen.


Peter
Gast #1896814
Lesenswert?

> Gibt es eine Lösung ohne goto ;-)


1
void f()
2
{
3
for (Schleifenbedingung)
4
   {
5
    Befehl;
6
    Befehl;
7
    while (Bedingung)
8
       {
9
        Befehl;
10
        if (Abfrage) return; //verlasse beide Schleifen
11
        Befehl;
12
       }
13
   }
14

15
}

?
Gast #1897105
Lesenswert?

ich wette, dass 10k mal öfter gesagt wird goto ist scheiße, als 
verkackter code mit goto gelesen wird.

oder:

ich wette, dass 99% der leute, die sagen goto ist verpönt, noch nie 
verkackten goto-code gesehen haben.
Gast #1897151
Lesenswert?

1
#define gehezu goto
und schon ist das goto weg ;-)

wenn es passt und den code leserlicher gestaltet, verwende es.
weenn es dein code ist - mach was du willst, wenn dir dein arbeitgeber 
ein goto verbieten möchte/verbietet hast du zwei möglichkeiten:
- gut argumentieren und eine rebellion veranstalten
- akzeptieren und hässliche/schlecht lesbare/sonstige workarounds 
einbauen...
Gast #1897153
Lesenswert?

Peter Dannegger schrieb:
> Die mit Return kostet etwas Stack, ist aber gleich gut leserlich, wie
> das Goto. Und dann kommen aber die Nörgler, die sagen, daß jede Funktion
> nur ein Return haben soll.

Jepp, und die Nörgler haben oft recht. Wie toll ist es wenn Du am Ende 
einer Funktion einen Breakpoint setzen willst und musst dann 2 oder 3 
oder 7 setzen, weil entsprechend viele returns da sind.
Wie toll ist es wenn du am Ende der Funktion schnell einen Trace 
rausschreiben willst und kannst auch das dann 3 oder gar 7 mal machen.

Peter Dannegger schrieb:
> Die mit ner Variable macht den Code deutlich unleserlicher und kann
> sogar richtig teuer werden, wenn extra für diese zusätzliche Variable
> ein Stackframe angelegt werden muß.

Der Code von Markus war keinen Deut schlechter. In Sachen Effizienz gabe 
ich dir 100% recht, wobei das auf µCs manchmal eine Rolle spielt, auf 
PCs nur in absoluten Ausnahmefällen.

Peter Dannegger schrieb:
> Man sollte Goto nicht unnütz nehmen. Wenn es aber paßt, wie die Faust
> aufs Auge, dann nimmt man es einfach.
>
> Irgendwelche Dogmen auszusprechen und sich sklavisch daran
> festzukrallen, halte ich für Schwachsinn. Der gesunde Menschenverstand
> sollte Vorrang haben.

100% agree, deshalb habe ich oben auch nur oft gesagt :-)

benjamin tülpchen schrieb:
> ich wette, dass 99% der leute, die sagen goto ist verpönt, noch nie
> verkackten goto-code gesehen haben.

Ich habe mal ein paar Jahre Code warten müssen, der von einem 
selbstgeschriebenen Cross-Compiler (nicht von mir) aus IBM-Host 
Assembler C für Unixsysteme und Windows und OS/2 erzeugt hat. So grausam 
kann kein Mensch C Spagetticode programmieren, nicht mal einer der sonst 
nur Basic programmiert hat :-).

Gruß
Gast #1897372
Lesenswert?

Ein "goto" ist wie Gift, genauso wie vieles gute in Medizin. Es gibt
Programme die dankt dem Befehl gut strukturiert und gut lesbar sind.
Z.B. am Anfang prüft man die Plausibilität von sehr vielen Angaben. Wenn 
etwas nicht passt dann lädt man Puffer für Anzeige eine Meldung und mit 
einem Sprung „goto Ergebnis“ verlässt man egal wie tief verschaltete 
Schleife. Im Ergebnis prüft man dann ob etwas zum Schlissen (geöffnete 
Files) oder zum Freigeben (Speicher).
Gast #1897381
Lesenswert?

U.R. Schmitt schrieb:
> Peter Dannegger schrieb:
>> Die mit Return kostet etwas Stack, ist aber gleich gut leserlich, wie
>> das Goto. Und dann kommen aber die Nörgler, die sagen, daß jede Funktion
>> nur ein Return haben soll.
>
> Jepp, und die Nörgler haben oft recht. Wie toll ist es wenn Du am Ende
> einer Funktion einen Breakpoint setzen willst und musst dann 2 oder 3
> oder 7 setzen, weil entsprechend viele returns da sind.
> Wie toll ist es wenn du am Ende der Funktion schnell einen Trace
> rausschreiben willst und kannst auch das dann 3 oder gar 7 mal machen.

Da lässt sich aber drüber streiten. Man kann eine Funktion auch ganz 
schön unübersichtlich machen, wenn man aus Krampf nur ein return haben 
möchte. Das gibt dann auch gerne Spaghetticode. Der Königsweg wäre 
natürlich, per goto zu einem Return zu springen ;-)

Nico
#1897388
Lesenswert?

Die Qunitessenz ist wie so oft:

Diese Daumenregeln sind grundsätzlich nicht schlecht. Sie geben einem 
Anfänger Richtlinien, wie er die gröbsten Source-Code Fehler vermeiden 
kann. Beachtet man sie, dann läuft man nicht so leicht in Gefahr den zu 
Recht gefürchteten 'Spaghetti-Code' zu produzieren.

Aber wie so oft sind derartige Regeln nicht als Dogma zu sehen, von dem 
man nicht im Einzelfall abweichen kann, solange man weiß was man tut und 
einen guten Grund dafür hat.
#1897393
Lesenswert?

Also ich hasse generell Schleifen, die mittendrin verlassen werden. Das 
ist immer schwer zu verstehen. Das obige Beispiel würde ich selbst daher 
so schreiben:
1
for (Schleifenbedingung)
2
   {
3
    short running = 1;
4

5
    while(running)
6
      {
7
        Befehl;
8
        Befehl;
9
         while (Bedingung && running)
10
          {
11
            Befehl;
12
            if (running = !Abfrage))
13
             {
14
               Befehl;
15
             }
16
          }
17
   }
Gast #1897410
Lesenswert?

Nico22 schrieb:
> Da lässt sich aber drüber streiten. Man kann eine Funktion auch ganz
> schön unübersichtlich machen, wenn man aus Krampf nur ein return haben
> möchte. Das gibt dann auch gerne Spaghetticode.

Jepp, ganz klar, wie Peter gesagt hat:
> Irgendwelche Dogmen auszusprechen und sich sklavisch daran
> festzukrallen, halte ich für Schwachsinn. Der gesunde Menschenverstand
> sollte Vorrang haben.

> Königsweg wäre natürlich, per goto zu einem Return zu springen ;-)
***ROFL***

Das ist in java toll. Du klammerst das mit einem try finally und kannst 
dort dann alles sauber beenden, egal wie verschachtelt das Ganze ist.
Das ist nämlich das nächste Problem mit mehreren returns. Du hast eine 
komplexere Aktion, z.B: liest Du aus einer Datei/Dateien und/oder 
MQ-Queues Daten und speicherst Sie (abhängig von dem was Du gelesen 
hast, also komplexe Bedingungen und ggf. Schleifen) in eine Datenbank 
und oder andere Queues. Am Ende musst Du alles aufräumen und je nachdem 
ob es geklappt hat in MQ und Datenbank commit oder rollback absetzen. 
Dann noch mehrere Returns und deine Funktion/Methode wird nie richtig 
funktionieren.
Mit try finally problemlos in den Griiff zu kriegen.

Aber Java in µCs ist auch nicht meine Präferenz :-)
Gast #1897434
Lesenswert?

U.R. Schmitt schrieb:
>> Königsweg wäre natürlich, per goto zu einem Return zu springen ;-)
> ***ROFL***
>
> Das ist in java toll. Du klammerst das mit einem try finally und kannst
> dort dann alles sauber beenden, egal wie verschachtelt das Ganze ist.

Solange dich nicht interessiert, wo innerhalb des Blocks die Exception 
aufgetreten ist. Sonst mußt du halt um jede Funkton ein eigenes try 
setzen.

> Das ist nämlich das nächste Problem mit mehreren returns. Du hast eine
> komplexere Aktion, z.B: liest Du aus einer Datei/Dateien und/oder
> MQ-Queues Daten und speicherst Sie (abhängig von dem was Du gelesen
> hast, also komplexe Bedingungen und ggf. Schleifen) in eine Datenbank
> und oder andere Queues. Am Ende musst Du alles aufräumen und je nachdem
> ob es geklappt hat in MQ und Datenbank commit oder rollback absetzen.
> Dann noch mehrere Returns und deine Funktion/Methode wird nie richtig
> funktionieren.
> Mit try finally problemlos in den Griiff zu kriegen.

Mit goto auch.

> Oh ja, finally fehlt mir in C++.

Warum? Dank vernünfig funktionierender Destruktoren braucht man das doch 
gar nicht.
#1897461
Lesenswert?

z.B. schlichte Debugausgaben nach dem Motto "ich komme gerade hier 
vorbei und springe zurück..." oder halt alles, was mit Aufräumen zu tun 
hat.

Letzteres kann man natürlich immer in einem dtor verpacken, aber
das lohnt nicht in jedem Fall.

Also hat man dann doch manchmal in mehreren catch-Zweigen mehr
oder weniger Codewiederholung, die in einem finally-Block besser
aussehen würden.

Nachtrag: am ehesten vermisse ich es dann, wenn ich etwas machen
will, was nicht direkt mit der eigentlichen Programmlogik verwebt
ist, z.B. Laufzeitmessung eines Algos.
Gast #1897621
Lesenswert?

Klaus Wachtler schrieb:
> ok, daß der Grund für finally in Java ein übler ist, macht
> den Mechanismus ja nicht per se schlecht.

Genau darum ging es mir. Wenn man nicht Lust hat, jedes 
C-init()-und-end() in eine eigene Klasse zu kapseln (was natürlich sehr 
elegant ist), dann vermisst man das finally manchmal schon. Es geht 
natürlich auch ohne.

Gruß,
Nico
#1897625
Lesenswert?

Klaus Wachtler schrieb:
> @Rolf Magnus:
> ok, daß der Grund für finally in Java ein übler ist, macht
> den Mechanismus ja nicht per se schlecht.

Ganz sicher nicht.

Aber wenn man erst mal auf RAII aufgesprungen ist und das konsequent 
macht, will man es nicht mehr missen. Und dann lösen sich 99% aller 
finally Probleme, genauso wie 99% aller Memory Leaks in Luft auf und man 
vermisst einen GC plötzlich überhaupt nicht mehr :-) Und eigentlich ist 
es ja der GC, im Zusammenspiel mit einem unbrauchbaren Destruktor, der 
einem Dinge wie finally aufzwingt.
Gast #1897645
Lesenswert?

Rolf Magnus schrieb:
> Ich sehe es eher als Krücke, die man eingebaut hat, weil die
> Destruktoren fehlen.

Sorry aber das ist ziemlicher Blödsinn.
Mit finally kann man auch innerhalb einer Methode viel feiner granuliert 
Dinge 'zum lokalen' Schluß beenden.
Und komm mir nicht mit OO-Designtheorien daß dann das Design falsch ist 
und man einzelne Klassen mit jeweils einem Destruktor machen müsste.
Man kann den Spiess auch umdrehen und sagen, C++ hat die Destruktor 
Krücke weil ...
Ausserdem wollte ich hier keine "die Programmiersprache ist besser 
weil..." Diskussion lostreten.
Aber es fühlen sich manche immer wieder ans Bein gepinkelt, wenn man 
"Ihr" System, Sprache, Tool angeblich schlecht macht, nur weil man wagt 
darauf hinzuweisen, daß es bei einem anderen Tool, System, Sprache, ... 
andere Konzepte gibt.
Viel Spass
#1897654
Lesenswert?

U.R. Schmitt schrieb:

> Aber es fühlen sich manche immer wieder ans Bein gepinkelt, wenn man
> "Ihr" System, Sprache, Tool angeblich schlecht macht, nur weil man wagt
> darauf hinzuweisen, daß es bei einem anderen Tool, System, Sprache, ...
> andere Konzepte gibt.

Genau darum gehst letztenendes.
In C++ gibt es kein finally, weil man in C++ anders programmiert.

Das hat doch nichts mit 'ans Bein pinkeln zu tun'.
Das muss man den Leuten einfach nur vermitteln, die zb von Java zu C++ 
kommen. Manche Idiome funktionieren in C++ nun mal anders. Und ehe man 
nach Möglichkeiten einer 1:1 Übersetzung sucht, sollte man besser auf 
die in der Zielsprache üblichen und bewährten Idiome umschwenken. In C++ 
ist es nun mal der Destruktor, der Aufräumarbeiten erledigt. Das hat den 
Vorteil, dass man als Verwender einer Klasse nicht darauf vergessen kann 
die entsprechende Funktion aufzurufen und man sich daher auch nicht 
darauf konzentrieren muss.

Um einen deutschen Text ins englische zu übertragen, reicht es auch 
nicht aus einfach nur Grammatik und Vokabeln zu beherrschen.
Gast #1898154
Lesenswert?

@Detlev T.:

ja, so ähnliche mache ich das auch. Wenn man gute Bezeichner wählt, ist 
es übersichtlich und logisch. Evtl. ein klein wenig ineffizienter als 
andere Lösungen, aber schön.


@Markus:

>for (i=0; (i<4)&&(!abbruch); i++)

Hmmm, gefällt mir nicht sooo gut. for-Schleifen verwende ich nur, wenn 
die Abbruchbedingung feststeht (z.B. Anzahl der Elemente eines Arrays 
etc.)
Sonst verwende ich lieber eine while- oder do-while-Schleife.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren