Forum: Mikrocontroller und Digitale Elektronik goto verpönt - was dann nehmen?


von Paul (Gast)


Lesenswert?

Hallo
in meinen Programmen nehme ich sehr häufig
1
void aufruf()
2
{ 
3
... tu was
4
}
mit einem Aufruf aus meinem Programm heraus.
void hat aber die Eigenschaft, dort weiter zu machen, von wo es 
aufgerufen wurde, es kehrt also zurück.
Wenn ich goto nutze, ergibt es teilweise eine totale 
Unübersichtlichkeit. Ist schlecht nachzuvollziehen wo es weiter geht.
Im Netz wird da von gesprochen, das es verpöönt ist nichrr genutzt 
werden soll.
Was nutz ihr bei solchen Sachen?
Paul

: Bearbeitet durch Moderator
von Peter II (Gast)


Lesenswert?

Paul schrieb:
> Was nutz ihr bei solchen Sachen?

keine Ahnung, dafür musst du uns erst mal zeigen wozu du goto brauchst. 
In deinem Beispiel ist das nicht klar.

von Kaj (Gast)


Lesenswert?

Paul schrieb:
> void hat aber die Eigenschaft
Das hat nichts mit void zu tun. void ist der Rueckgabe wert. Du 
koenntest genauso gut int statt void hinschreiben, das verhalten waere 
dasselbe.
Besorg dir erstmal ein C-Buch.

von Stefan F. (Gast)


Lesenswert?

Goto ist ein unnötiges Konstrukt. Wenn das Programm nach Ende einer 
Funktion nicht "normal" fortgesetzt werden soll, lifert man mit return 
einen entsprechenden Statuscode zurück und wertet den aus.
1
// returns 1 on success
2
uint8_t tuwas()
3
{
4
    ...
5
    if (whatever problem)
6
    {
7
       return 0;
8
    }
9
    ...
10
    return 1;
11
}
12
13
void caller()
14
{
15
    uint8_t success=tuwas();
16
    if (success)
17
    {
18
       tuNochwas();
19
    }
20
    else
21
    {   
22
       reagiereAufFehler();
23
    }
24
}


Für schleifen gibt es noch break und continue, um den normalen Ablauf zu 
unterbrechen.

von Paul H. (powl)


Lesenswert?

Ein guter Paul schaut lieber nach bevor er es gleich zwei mal falsch 
macht ;-)

http://www.duden.de/rechtschreibung/verpoent

von Jörg M. (derlang)


Lesenswert?

Häh?
Was?
Da steht nichts, was man ansatzweise verstehen könnte.

Wo nutzt du dort ein goto?

Und ja, ich behaupte auch, wer goto in einer höheren Programmiersprache 
nutzt, hat es nicht verstanden.

Oben steht eine Methode/Funktion, die kann aufgerufen werden und gibt 
halt keine Wert zurück.

Gib ein besseres Beispiel und man kann dir andere Lösungsmöglichkeiten 
bieten.

Ach ja, werft den Purschen zu Poden... verpöönt=>verpönt

von Dirk B. (dirkb2)


Lesenswert?

Paul schrieb:
> Was nutz ihr bei solchen Sachen?

for, while, do-while, if-else, return, break

von Stefan F. (Gast)


Lesenswert?

> Ist schlecht nachzuvollziehen wo es weiter geht.

Dabei hilft Dir die Entwicklungsumgebung. In Eclipse klickst du mit der 
rechten Maustaste auf den namen der Funktion, dann aus 
References/Project. Und schon werden alle Stellen aufgelistet, wo diese 
Funktion verwendet wird.

von Peter II (Gast)


Lesenswert?

Jörg M. schrieb:
> Und ja, ich behaupte auch, wer goto in einer höheren Programmiersprache
> nutzt, hat es nicht verstanden.

oder er nutzt die alle Möglichkeiten die eine Sprache bietet, statt sich 
komplizierten code zu schreiben nur um ein goto zu vermeiden.

von Dirk B. (dirkb2)


Lesenswert?

Stefan U. schrieb:
>> Ist schlecht nachzuvollziehen wo es weiter geht.
>
> Dabei hilft Dir die Entwicklungsumgebung. In Eclipse klickst du mit der
> rechten Maustaste auf den namen der Funktion, dann aus
> References/Project. Und schon werden alle Stellen aufgelistet, wo diese
> Funktion verwendet wird.

Werden auch die Sprungziele bei goto gezeigt?
(darum geht es hier)

von Stefan F. (Gast)


Lesenswert?

µIP nutzt viele Goto Befehle, das hat mich echt geschockt. Ich dachte 
bis dahin immer, das es in C gar kein Goto gäbe.

Aber immerhin ist der Code von µIP noch nicht so schlimm, das ich ihn 
als Spaghetti-Code bezeichnen würde. Da geht es noch einigermaßen, weil 
es ein simpler Batch-Ablauf ist, den man von oben nach unten lesen kann.

von Paul (Gast)


Lesenswert?

Danke für den Hinweis mit dem C-Buch.
Es gibt Leute die verstehen die Frage sofort und der Hinweis hat sofort 
geholfen. Sorry hatte das vergessen oder zu wenig genutzt.
Angere pöbeln lieber rum und geben irgend welche Sinnlose oder Hirnlose 
Komentare ab.
Danke Stefan
Paul

von Matze (Gast)


Lesenswert?

Schaut euch mal den Linux-Code an. Da gibt es sehr viele Goto's ;)

Wenn man weiß, wie man damit seinen Code übersichtlicher machen kann, 
dann spricht doch nichts gegen die Verwendung, oder?

von Stefan F. (Gast)


Lesenswert?

> Werden auch die Sprungziele bei goto gezeigt? (darum geht es hier)

Achso, Frage missverstanden.
Keine Ahnung, ich habe Goto noch nie benutzt.

Ich wollte es gerade ausprobieren, aber ich kriege das C++ Plugin nicht 
heruntergeladen. Habe momentan nur Java installiert.

von Bellis Perennis (Gast)


Lesenswert?

>goto verpönnt - was dann nehmen?

Lieber GITTI als GOTO.

von Sebastian (Gast)


Lesenswert?

Hallo,

man kann goto schon verwenden, aber man sollte es nicht übertreiben und 
man sollte aufpassen.Im Zweifelsfall, Finger weg.

Zu goto:

- Sinnvoll an Stellen an denen es die Komplexität extrem erhöhen würde.
- Sprünge mit goto sollten immer vorwärts im Controlflow sein.
- Das Sprung-label sollte in der selben Funktion sein.

Falls Du Einsteiger bist:

- "Head First C", weniger Abstrakt als MISRA und ein bisschen mehr Spaß.

Besorge Dir MISRA-C 2012 und das K&R C Buch:

- "The C Programming Language", sollte man haben.

- "MISRA-C 2012"ist der Standard wenn es um C geht, alles andere sind 
meist Abwandlungen davon und meist in der gesamtheit nicht wirklich 
besser. Die 2012er Version hat gegenüber der 2004er einige 
Verbesserungen, vor allem bei der Verständlichkeit

Grüße

Sebastian

von Clemens M. (panko)


Lesenswert?

Ich habe goto schon hin und wieder benutzt. Z.B. um in einer größeren 
Funktion vorzeitig Fehler aufzuräumen.

z.B aus den Fingern gesogen ein Beispiel um etwas vorzeitig abzubrechen.

int complex_io_operation(wchar_t *file, struct *data_block)
{
  if( (Open(file) != 0)) {
    goto ERROR_1; /* not found? */
  }

  if( AppendData(data_block) != data_block->size ) {
    goto ERROR_2; /* insufficient data written */
  }

 (...)

  return 0;


ERROR_1:
  /* individual cleanup code 1 */
  return -1;
ERROR_2:
  /* individual cleanup code 2 */
  return -2;
}


Möglicherweise ein schlechtes Beispiel. Womöglich nicht 
Lehrbuch-konform. Man könnte das natürlich anders schreiben, umbiegen 
etc.,  aber ich finde so ist es gut lesbar.

Dogmatische Regeln, die im Extremfall auch nur zitiert werden und 
vorgegeben wurden, bremsen einen im Zweifel nur aus.
Man muss alles immer wieder auf den Prüfstand stellen finde ich.

von Heinz L. (ducttape)


Lesenswert?

Nun, angesichts dessen dass Du uns sehr wenig Code zum Arbeiten gibst, 
kannst Du uns so ein Goto-Konstrukt mal posten? Ich wette um eine 
Eiswaffel dass sich dies mit einem der von dirkb2 vorgeschlagenen 
Konstrukte lückenlos und weit übersichtlicher ersetzen läßt.

von MaWin (Gast)


Lesenswert?

Paul schrieb:
> in meinen Programmen nehme ich sehr häufigvoid aufruf()
> {
> ... tu was
> }
> mit einem Aufruf aus meinem Programm heraus.
> void hat aber die Eigenschaft, dort weiter zu machen, von wo es
> aufgerufen wurde, es kehrt also zurück.
> Wenn ich goto nutze, ergibt es teilweise eine totale
> Unübersichtlichkeit. Ist schlecht nachzuvollziehen wo es weiter geht.
> Im Netz wird da von gesprochen, das es verpöönt ist nichrr genutzt
> werden soll.
> Was nutz ihr bei solchen Sachen?

Ein C-Buch um erst mal die Grundlagen zu erlernen.

Was du geschrieben hast, ist eine Prozedur (das ist die Bedeutung von 
void, mit allem anderen wäre es eine Funktion), und die macht ebenso wie 
eine Funktion nach einem Aufruf IMMER dort weiter, von wo sie aufgerufen 
wurde. Das ist Absicht. Das haben die mit Mühe (einem Stack der 
Rücksprungadressen) so gemacht.

Man springt auch nicht aus Prozeduren und Funktionen mit GOTO raus um 
irgendwo anders hinzukommen, denn dann könnte man sie nicht mehrmals an 
unterschiedlichen Stellen verwenden. Das ist der einzige wirkliche 
Grund, etwas in eine Prozedur zu verpacken: Damit man dasselbe an 2 
unterschiedlichen Stellen benutzen kann.

Wenn du dein ...tu was verpackt in aufruf sowieso nur ein Mal im 
Programm per aufruf() aufrufst, brauchst du es gar nicht erst in eine 
Prozedur zu verpacken, schreibe statt aufruf() gleich ....tu was dort 
hin.

In fortgeschrittenem C lernt man vielleicht setjmp/longjmp, aber das nur 
zur Fehlerbehandlung, in C++ sind das Exceptions.

Aber du steckst offenbar noch in grundlegendem Programmieren und 
verpennter deutscher Rechtschreibung fest.

von Thomas E. (picalic)


Lesenswert?

Dirk B. schrieb:
> for, while, do-while, if-else, return, break

switch-case hast Du vergessen - das kommt der "klassischen" 
goto-Funktion wohl noch am nächsten.

von Jörg M. (derlang)


Lesenswert?

Peter II schrieb:
> Jörg M. schrieb:
>> Und ja, ich behaupte auch, wer goto in einer höheren Programmiersprache
>> nutzt, hat es nicht verstanden.
>
> oder er nutzt die alle Möglichkeiten die eine Sprache bietet, statt sich
> komplizierten code zu schreiben nur um ein goto zu vermeiden.

Nur weil eine Programmiersprache alte Relikte weiter beinhaltet, heißt 
es nicht, dass man diese auch nutzen sollte. Wenn man ein goto benötigt, 
um "komplizierten" Code zu vermeiden, hat man schon vorher den 
Grundstein für zu komplizierten Code gelegt.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

> Werden auch die Sprungziele bei goto gezeigt? (darum geht es hier)

Ich hab's jetzt testen können.

Drücke die Strg Taste und klicke dann auf dem Namen des Sprungziels 
hinter Goto. Der Cursor springt das zum Ziel und Eclipse markiert es.

von Joachim B. (jar)


Lesenswert?

Jörg M. schrieb:
> Und ja, ich behaupte auch, wer goto in einer höheren Programmiersprache
> nutzt, hat es nicht verstanden.

hmmm ich habe einen Fall wo ich trotz C goto verwende, vielleicht gehts 
auch anders, ich weiss es nicht.

Ich muss das Beispiel noch mal suchen, aber ich gebe zu goto in C 
braucht man eigentlich nicht, aber weil es das doch gibt und ich auch 
schon einmal darauf zurückgreifen musste mangels anderer Ideen kann es 
nicht so sinnlos sein.

Den jmp gibts ja in Asm auch, also warum goto verteufeln?

von Peter II (Gast)


Lesenswert?

Jörg M. schrieb:
>> oder er nutzt die alle Möglichkeiten die eine Sprache bietet, statt sich
>> komplizierten code zu schreiben nur um ein goto zu vermeiden.
>
> Nur weil eine Programmiersprache alte Relikte weiter beinhaltet, heißt
> es nicht, dass man diese auch nutzen sollte. Wenn man ein goto benötigt,
> um "komplizierten" Code zu vermeiden, hat man schon vorher den
> Grundstein für zu komplizierten Code gelegt.

goto bei C (nicht C++) zur Fehlerbehandlung ist üblich und sinnvoll.

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

https://silviocesare.wordpress.com/2007/10/24/a-good-use-of-goto-for-error-handling/

von Heinz L. (ducttape)


Lesenswert?

Joachim B. schrieb:

> Den jmp gibts ja in Asm auch, also warum goto verteufeln?

Und jedesmal wenn er nicht im Sinne eines while/for-repeaters verwendet 
wird oder zum Überspringen eines if-Astes gibt's Ärger.

von Matze (Gast)


Lesenswert?

Peter II schrieb:
> goto bei C (nicht C++) zur Fehlerbehandlung ist üblich und sinnvoll.
>
> http://eli.thegreenplace.net/2009/04/27/using-
> goto-for-error-handling-in-c
>
> 
https://silviocesare.wordpress.com/2007/10/24/a-good-use-of-goto-for-error-handling/

Wird auch im Kapitel 7 des "Linux kernel coding style" so beschrieben:

https://www.kernel.org/doc/Documentation/CodingStyle

von Jan K. (madengineer)


Lesenswert?

Peter II schrieb:
> goto bei C (nicht C++) zur Fehlerbehandlung ist üblich und sinnvoll.

Definitiv, hab ich auch gestern erst so für eine I2C Routine so genutzt.
Da wurde zu erst ein Konfigurationsbyte ausgelesen, ein paar Bits 
ausmaskiert und neue Bits gesetzt und das Byte wieder zurück 
geschrieben. Der Rückgabewert der Funktion zeigt den Erfolg oder 
Misserfolg an.
Hier gab es auch viele Stellen, wo Fehler auftreten können. Wenn zum 
Beispiel ein Buszugriff fehlschlägt, muss man vor dem Return noch den 
i2c_stop() aufrufen, um den Bus wieder freizugeben. Das Ergebnis war im 
ersten Schritt ein furchtbarer Spaghetti Code. Im zweiten Schritt konnte 
dank goto sehr stark aufgeräumt werden. Man springt einfach in den 
Aufräumbereich am Ende der Funktion, nach dem return 1.
Das ganze lässt wirklich gut erweitern, wie Peter hier verlinkt hat:

https://silviocesare.wordpress.com/2007/10/24/a-good-use-of-goto-for-error-handling/

MaWin schrieb:
> In fortgeschrittenem C lernt man vielleicht setjmp/longjmp, aber das nur
> zur Fehlerbehandlung, in C++ sind das Exceptions.

Das ganze war ein sehr interessanter Einwurf, der bisher hier nicht 
weiter  aufgegriffen wurde. Ich habe diese beiden Funktionen auch schon 
mal gesehen, aber nie wirklich wahrgenommen, nie hinterfragt, geschweige 
denn benutzt. Ich denke das wird wohl den meisten so gehen, aber das 
Interesse war geweckt und ich habe aber nun mal etwas gegoogled und bin 
hierüber gestolptert:

http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html

Hier wurde ein komplettes Try-Catch-Finally-Kontrukt über etwas 
Preprocesssor-Magic gebaut. Das ganze macht echt einen guten und 
durchdachten Eindruck. Hat schon jemand Erfahrung mit solch einer 
Konstruktion?

von Heinz L. (ducttape)


Lesenswert?

Oder einfacher der erste Code ohne Goto:
1
#define NUMBER_OF_VARS 4
2
#define A_OK 1
3
#define ERROR 0
4
static char* a[NUMBER_OF_VARS];
5
6
int do_initialize()
7
{
8
   for (i=0;i<NUMBER_OF_VARS;i++)
9
   {
10
      if (!(a[i]=malloc(10))
11
        return ERROR;
12
   }
13
   return A_OK;
14
}
15
16
void do_cleanup()
17
{
18
  int i=0;
19
  while (a[i])
20
    free (a[i++]);
21
}
22
23
int main()
24
{
25
  if (do_initialize() == ERROR)
26
    do_cleanup();
27
}

Der Grund warum das funktioniert ist einfach: malloc gibt einen 
Nullpointer zurück wenn es failt.

Also wer einen guten Grund für goto sucht muss weitersuchen, hier gibt's 
leider keinen.

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Joachim B. schrieb:
> hmmm ich habe einen Fall wo ich trotz C goto verwende

Es gibt halt Sachen im Leben, die man besser niemandem sagen oder zeigen 
sollte.

> Den jmp gibts ja in Asm auch, also warum goto verteufeln?

Es ist ein Wortsuchspiel, man muss den Label erst mal finden im 
Quelltext. Das ist unübersichtlich. (Auch) daher ist ASM 
unübersichtlich. Schade, daß du das nicht selber bemerkst.


Dann auch noch aus einer Prozedur zu springen wie Paul es vor hat, ist 
ganz schlechter Programmierstil. Das macht man höchstens, wenn man ein 
Programm nach Fehler hart abbrechen will (exit). Das passiert bei einem 
uC nie, was soll auch nach dem das Programm endet passieren ?

von Clemens M. (panko)


Lesenswert?

Setjmp auf einem uc finde ich gerade in Verbindung mit Interrupts recht 
gefährlich. Da legt man sich schnell ein Ei mit falschem Kontext oder 
falschen Flags.

von Joachim B. (jar)


Lesenswert?

MaWin schrieb:
> Es gibt halt Sachen im Leben, die man besser niemandem sagen oder zeigen
> sollte.

stimmt du hast so recht

Beitrag "Re: Relais Ersatz in kleinster Bauform"

MaWin schrieb:
> Dann auch noch aus einer Prozedur zu springen

da hast du auch recht, das mache ich nicht und da sollte man goto auch 
nicht verwenden.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

Matze schrieb:
> Wenn man weiß, wie man damit seinen Code übersichtlicher machen kann,
> dann spricht doch nichts gegen die Verwendung, oder?

Was im Endeffekt heißt: Als Anfänger lässt man gefälligst die Finger 
davon. ;-)

von foobar (Gast)


Lesenswert?

Es gibt schon einen Grund warum goto verpönt ist, bei übermäßigen 
Einsatz macht es ein Programm unwartbar.
Gerade wenn jemand programmieren lernt, sollte er darauf verzichten. 
Wenn man weiß was man tut, dann kann ein goto durchaus Sinn machen.
zB der klassische Ressourcenstackabbau im Fehlerfall. Das verringert 
dann die Einrückungsebenen.

von Third E. (third-eye)


Lesenswert?

Mir fällt ein spezieller Fall ein, wo goto bei Error Handling 
tatsächlich Sinn macht:
Man könnte zwar den Aufräum-Code in eine separate Funktion packen, wie 
im Code von Heinz L.. Dies hat aber zusätzliche Funktionsaufrufe zur 
Folge, was Ausführungszeit und Kompilatgröße betrifft. Zumindest, wenn 
der Aufräumcode von mehreren Stellen aus aufgerufen wird.
Ich habe mal einen Fall mitbekommen, wo es auf jedes eingesparte 
Flash-Byte ankam. Wegen sehr großer verbauter Stückzahl war es nicht 
möglich, einfach den nächstgrößeren µC zu verwenden.

von Falk B. (falk)


Lesenswert?

Eine Renaissance des Goto? OMG!

Rein syntaktisch ist Goto in C vollkommen überflüssig. Praktisch ist es 
nur in EXTREM wenigen Situationen gerechtfertigt.

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
> Praktisch ist es
> nur in EXTREM wenigen Situationen gerechtfertigt.

sag ich doch, selten wenn man weiss warum oder man keine andere Lösung 
sieht, das heisst ja nicht das es nicht auch ohne goto ginge, aber 
manchmal geht Ergebnis vor Schönheit.

von Stefan F. (Gast)


Lesenswert?

> zB der klassische Ressourcenstackabbau im Fehlerfall.

Den Ressourcenstackabbau  implementiere ich (in allen Sprachen) anders. 
Beispiel in Pseudo-Code:

1
File input=0;
2
File output=0;
3
Converter converter=0;
4
try
5
{
6
  input=new File("filename1");
7
  output=new File("filename2");
8
  converter=new Converter(params);
9
  while (input.hasMore())
10
  {
11
    line=input.readLine();
12
    output.writeLine(converter.convert(line));
13
  }
14
}
15
finally
16
{
17
  if (converter!=0) converter.close();
18
  if (output!=0) output.close();
19
  if (input!=0) input.close();
20
}

Anmerkung: In diesem beispiel gehe ich davon aus, dass die close 
Methoden niemals Exceptions werfen. Ansonsten müsste ich sie einzeln 
abfangen.

von TestX (Gast)


Lesenswert?

@third-eye

dafür gibt es inline funktionen...schon ist der overhead raus

von Peter II (Gast)


Lesenswert?

Stefan U. schrieb:
> Den Ressourcenstackabbau  implementiere ich (in allen Sprachen) anders.

und in Sprachen ohne Exception/Finaly?

von MaWin (Gast)


Lesenswert?

Stefan U. schrieb:
> Beispiel in Pseudo-Code:

Das fällt aber unter die schlechten Beispiele aus dem Gruselkabinett des 
codens.

Da gehören 3 try/catch Blöcke hin (ein 4. für das while).

von Diodenes (Gast)


Lesenswert?

Paul schrieb:

> goto verpönnt - was dann nehmen?

> Im Netz wird da von gesprochen, das es verpöönt ist nichrr genutzt
> werden soll.
> Was nutz ihr bei solchen Sachen?

COME FROM

http://catb.org/esr/intercal/ick.htm#COME-FROM-and-NEXT-FROM
https://de.wikipedia.org/wiki/INTERCAL

;-)

von nicht"Gast" (Gast)


Lesenswert?

MaWin schrieb:
> Da gehören 3 try/catch Blöcke hin (ein 4. für das while).

WAAAAS? (am Inroniedetektor rüttel, hoffentlich ist er kaputt)

Das einzige, was man hier bemängeln kann, ist dass keine 
Fehlerbehandlung erfolgt. Es gibt kein catch.

Wenn du meinst, dass man um jeden einzelnen Befehl ein try/catch machen 
soll tut mir der leid, der deinen Code lesen muss.

von Jay (Gast)


Lesenswert?

Heinz L. schrieb:
> Also wer einen guten Grund für goto sucht muss weitersuchen, hier gibt's
> leider keinen.

Ja, du hast auch die Aufgabenstellung leicht modifiziert und ein Array 
von Pointern genommen. Mieser Trick. Trotz des Tricks sieht deine Lösung 
ziemlich hässlich aus.

Da sind wir dann beim eigentlichen Punkt:

Ab wann ist Prinzipienreiterei wichtiger als klarer Code?

von Doh! (Gast)


Lesenswert?

Pro:
https://www.cs.sjsu.edu/~mak/CS185C/KnuthStructuredProgrammingGoTo.pdf
Contra:
https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF

Wenn zwei Turing Award Gewinner sich hier nicht einig waren, was besser 
ist (wohl weil jeder einen anderen Fokus hatte) bezweifle ich, dass man 
die Lösung hier erarbeiten kann.

von informatik student (Gast)


Lesenswert?

In der While-Programmiersprache gibt es kein goto, und die ist 
turingmächtig. Da es in C die While-Schleife gibt ist C auch (ohne goto) 
turingmächtig. Goto gibt es nur noch um kompatibel zu altem Code zu 
bleiben. Es gibt aber keinen Grund mehr es zu benutzen.

von Heinz L. (ducttape)


Lesenswert?

Jay schrieb:
> Heinz L. schrieb:
>> Also wer einen guten Grund für goto sucht muss weitersuchen, hier gibt's
>> leider keinen.
>
> Ja, du hast auch die Aufgabenstellung leicht modifiziert und ein Array
> von Pointern genommen. Mieser Trick. Trotz des Tricks sieht deine Lösung
> ziemlich hässlich aus.
>
> Da sind wir dann beim eigentlichen Punkt:
>
> Ab wann ist Prinzipienreiterei wichtiger als klarer Code?

Du hast 4 Variablen vom gleichen Typ die offensichtlich mehrere 
Gemeinsamkeiten haben, gleichzeitig initialisiert und zerstört werden 
sollen. Hier KEIN Array zu verwenden wäre selten dämlich.

Ehrlich gesagt find ich meine Lösung um Längen übersichtlicher als die 
Goto-Wurst vom Original. Soll ich's in ein Objekt verpacken damit der 
ganze "unschöne" Code wegabstrahiert wird?

von Peter II (Gast)


Lesenswert?

informatik student schrieb:
> In der While-Programmiersprache gibt es kein goto, und die ist
> turingmächtig. Da es in C die While-Schleife gibt ist C auch (ohne goto)
> turingmächtig. Goto gibt es nur noch um kompatibel zu altem Code zu
> bleiben.
was hat das eine mit dem anderen zu tun? Niemand bezweifelt das man ohne 
goto programmieren kann - aber dann teilweise umständlicher

> Es gibt aber keinen Grund mehr es zu benutzen.
doch, um code einfach und übersichtlich zu machen.

von Stefan F. (Gast)


Lesenswert?

> und in Sprachen ohne Exception/Finaly?
Um Exception Handling gings mir in meinem Beispiel gar nicht. Man kann 
auch in C vorzeitig aussteigen, um in den Aufräumblock zu kommen. Zum 
Beispiel in c
1
int result=ERROR;
2
void* input=0;
3
void* output=0;
4
void* converter=0;
5
do
6
{
7
   input=whatever;
8
   if (fehler) break;
9
   output=whatever;
10
   if (fehler) break;
11
   converter=whatever;
12
   if (fehler) break;
13
   ...
14
   tuwas
15
   if (fehler) break;
16
   ...
17
   result=SUCCESS;
18
} 
19
while(0);
20
if (converter) { close converter};
21
if (output) { close output};
22
if (input) { close input};
23
return result;


> Da gehören 3 try/catch Blöcke hin (ein 4. für das while).

Wenn die close() Aufrufe Exceptions werfen können, hast du Recht. In 
diesem Fall wollten wir allerdings nicht über das Eception Handling 
diskutieren, sondern über das Aufräumen von Ressourcen, die zum teil gar 
nicht belegt wurden.

> Das einzige, was man hier bemängeln kann, ist dass keine
> Fehlerbehandlung erfolgt. Es gibt kein catch.

Richtig. War Absichtlich ausgelassen.

von Doh! (Gast)


Lesenswert?

informatik student schrieb:
> Da es in C die While-Schleife gibt ist C auch (ohne goto)
> turingmächtig. Goto gibt es nur noch um kompatibel zu altem Code zu
> bleiben. Es gibt aber keinen Grund mehr es zu benutzen.

Du hast die Mächtigkeit einer Sprache / Maschine nicht verstanden.
Lese das Skipt nochmal und stelle heraus, was man mit der Mächtigkeit 
beschreibt und welche Aspekte eben nicht.

Stichworte:
- Menge der Lösbaren Probleme
- Struktur
- Beweisbarkeit / Verifikation
- Effizienz

PS: http://www.wolframscience.com/prizes/tm23/TM23Proof.pdf ist deiner 
Argumentation nach das Ultima Ratio, kann alles, warum also noch den 
alten komplizierten Kram benutzen?

von Jodel (Gast)


Lesenswert?

Stefan U. schrieb:
> Um Exception Handling gings mir in meinem Beispiel gar nicht. Man kann
> auch in C vorzeitig aussteigen, um in den Aufräumblock zu kommen. Zum
> Beispiel in c

Ein gutes Beispiel, wie man es nicht machen sollte. Du umgehst goto 
nicht, um schlechten Code zu vermeiden, du umgehst aus Prinzip und 
ersetzt es durch einen Missbrauch von while und erzeugst damit erst 
schlechten Code.

von MaWin (Gast)


Lesenswert?

Stefan U. schrieb:
> sondern über das Aufräumen von Ressourcen, die zum teil gar
> nicht belegt wurden

Daher schreibt man in C
1
File input=fopen("filename1");
2
if(input)
3
{
4
    File output=fopen("filename2");
5
    if(output)
6
    {
7
        Converter converter=NewConverter(params);
8
        if(converter)
9
        {
10
            while (input.hasMore())
11
            {
12
                line=input.readLine();
13
                output.writeLine(converter.convert(line));
14
            } 
15
            converter.close();
16
        }
17
        output.close();
18
    }
19
    input.close();
20
}
und weil wir in C++ Exceptions haben
1
try
2
{
3
    File input=new File("filename1");
4
    try
5
    {
6
        File output=new File("filename2");
7
        try
8
        {
9
            Converter converter=new Converter(params);
10
            try
11
            {
12
                while (input.hasMore())
13
                {
14
                    line=input.readLine();
15
                    output.writeLine(converter.convert(line));
16
                }
17
            }
18
            catch 
19
            {
20
                // jeweils geeignetes Errorhandling
21
            }
22
        }
23
    }
24
    // weil deallozierte Klassen sich von selbst (.close) aufzuräumen haben
25
}

von Sebastian V. (sebi_s)


Lesenswert?

MaWin schrieb:
> und weil wir in C++ Exceptions haben [...]

Ich bin mir nicht sicher ob das ein Beispiel sein soll oder eher zeigt 
wie man es genau nicht machen soll. Ich hoffe jedenfalls das so niemand 
C++ programmiert.

von corruptmemory (Gast)


Lesenswert?

Also goto kann sinnvoll sein nur muß man auch wissen was man damit 
anrichten kann.
Wer wild im Programm herumspringt kann sich schnell raceconditions oder 
schlimmeres einfangen.
Von malloc/free mal ganz abgesehen.
Assembler kann man mit passenden Sprungnamen sehr übersichtlich 
gestalten, gilt natürlich erst recht für Prozedurale oder OO Sprachen.
Das schöne an höheren Sprachen ist aber das sich der Compiler um das 
sichern und rücksichern der Register usw. kümmert, während man das in 
Assembler idR zu Fuß machen muß.
Wenn Du bei einem bestimmten Event etwas anderes als die nächste 
Funktion aufrufen willst, dann bietet sich das erwähnte switch/case an 
und das ganze als Statemachine um die Übergänge auch korrekt zu haben.
Wenn man ja wüßte wo das eigentliche Problem liegt (außer das keine C 
Kenntnisse vorliegen) ?

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

$ cd linux-src
$ grep -R "goto \\w\\+;" * | wc -l
124065

So schlimm kann die Verwendung von goto in C nicht sein wenn es im 
durchaus als qulitativ wertig anzusehenden Linux Kernel über 100k mal 
zum Einsatz kommt.

Matthias

von Bellis Perennis (Gast)


Lesenswert?

Μαtthias W. schrieb:
> So schlimm kann die Verwendung von goto in C nicht sein wenn es im
> durchaus als qulitativ wertig anzusehenden Linux Kernel über 100k mal
> zum Einsatz kommt.

Hehehe...
;-)

...und da sitzen sie mit offenem Mund vor dem Monitor und staunen, die 
SPEZIALISTEN.

von Dussel (Gast)


Lesenswert?

Μαtthias W. schrieb:
> So schlimm kann die Verwendung von goto in C nicht sein wenn es im
> durchaus als qulitativ wertig anzusehenden Linux Kernel über 100k mal
> zum Einsatz kommt.
Wobei ich annehme, dass der ziemlich hardwarenah programmiert ist und 
deshalb Konstrukte verwendet wurden, die man im Alltag nicht unbedingt 
verwenden sollte (wenn man im Alltag nicht gerade Kernelprogrammierer 
ist ;-) ).

Goto hat ja seine Berechtigung, nur eben absolut nicht für Anfänger, die 
damit Kontrollstrukturen umgehen wollen, 'weil es ja nicht anders geht'.

von Mark B. (markbrandis)


Lesenswert?

Μαtthias W. schrieb:
> So schlimm kann die Verwendung von goto in C nicht sein wenn es im
> durchaus als qulitativ wertig anzusehenden Linux Kernel über 100k mal
> zum Einsatz kommt.

Und wer programmiert Betriebssysteme? Genau - nur wenige Menschen. Und 
die wissen eben was sie tun.

von Mark B. (markbrandis)


Lesenswert?

Dussel schrieb:
> Goto hat ja seine Berechtigung, nur eben absolut nicht für Anfänger

Vollkommen richtig.

von Peter II (Gast)


Lesenswert?

Dussel schrieb:
> Wobei ich annehme, dass der ziemlich hardwarenah programmiert ist und
> deshalb Konstrukte verwendet wurden, die man im Alltag nicht unbedingt
> verwenden sollte (wenn man im Alltag nicht gerade Kernelprogrammierer
> ist ;-) ).

nein, nur ein kleiner Teil ist Hardware nah.

goto wird oft zum aufräumen verwendet. "goto error;"

von Peter II (Gast)


Lesenswert?

Mark B. schrieb:
>> Goto hat ja seine Berechtigung, nur eben absolut nicht für Anfänger
>
> Vollkommen richtig.

achso, Anfänger sollen also umständlichen Code schreiben und keine 
Resourcen aufräumen?

Die Beispiele von oben mit dem aufräumen von Resoucen kommen sehr oft 
auch bei Anfängern vor. Da ist goto das richtige mittel.

Das sollte Anfänger beachtet, wenn sie goto einsetzen:

Sebastian schrieb:
> - Sinnvoll an Stellen an denen es die Komplexität extrem erhöhen würde.
> - Sprünge mit goto sollten immer vorwärts im Controlflow sein.
> - Das Sprung-label sollte in der selben Funktion sein.

von Heinz L. (ducttape)


Lesenswert?

Mark B. schrieb:
> Μαtthias W. schrieb:
>> So schlimm kann die Verwendung von goto in C nicht sein wenn es im
>> durchaus als qulitativ wertig anzusehenden Linux Kernel über 100k mal
>> zum Einsatz kommt.
>
> Und wer programmiert Betriebssysteme? Genau - nur wenige Menschen. Und
> die wissen eben was sie tun.

Ohne das jetzt zum Win10-Hassthread umzuwidmen, aber war da nicht erst 
kürzlich was wo so 'n Systemupdate das System in den Orkus geschossen 
hat?

Oder die Möglichkeit bei einer Maschine auf der Linux läuft mittels 
Löschung der falschen Files in /proc nicht nur das OS sondern das BIOS 
so zu schrotten dass dabei ein teurer Briefbeschwerer rauskommt?

Also... auch OS-Progger bauen Mist, sind ja auch nur Menschen.

von danvet (Gast)


Lesenswert?

Um es mit dem Meistern zu sagen (Kernighan+Ritchie):
[Kapitel 3.8]
C verfügt auch über eine beliebig zu missbrauchende goto-Anweisung und 
Marken, zu denen gesprungen werden kann. Formal ist goto niemals 
notwendig, und man kann fast immer leicht ohne goto-Anweisung auskommen.
....
Mit einigen wenigen Ausnahmen, wie den hier zitierten, ist Code mit 
goto-Anweisungen im allgemeinen schwieriger zu verstehen und zu pflegen, 
als Code ohne goto. Wir wollen zwar nicht dogmatisch werden, aber es 
scheint doch, dass goto-Anweisungen wenn überhaupt, dann selten benutzt 
werden sollen.
[Kapitel Ende]

von Mark B. (markbrandis)


Lesenswert?

Peter II schrieb:
> achso, Anfänger sollen also umständlichen Code schreiben und keine
> Resourcen aufräumen?
>
> Die Beispiele von oben mit dem aufräumen von Resoucen kommen sehr oft
> auch bei Anfängern vor.

Doch wohl eher nicht auf Mikrocontrollern, wenn man gerade mit Mühe und 
Not seine erste LED blinken lässt. Vielleicht wenn man als Anfänger auf 
dem PC eine lineare Liste ausprogrammiert oder sowas in der Art.

Ich bezweifle dass die meisten Anfänger mit malloc() und fopen() wild um 
sich schmeißen. Jedenfalls wenn es um µC Programmierung geht.

: Bearbeitet durch User
von Jens G. (jensig)


Lesenswert?

@danvet (Gast)
>Um es mit dem Meistern zu sagen (Kernighan+Ritchie):
>[Kapitel 3.8]
>C verfügt auch über eine beliebig zu missbrauchende goto-Anweisung und
>Marken, zu denen gesprungen werden kann. Formal ist goto niemals
>notwendig, und man kann fast immer leicht ohne goto-Anweisung auskommen.

Was nun - "niemals", oder (negiert) "fast immer"?

von Walter S. (avatar)


Lesenswert?

Jens G. schrieb:
> Formal ist goto niemals
>>notwendig, und man kann fast immer leicht ohne goto-Anweisung auskommen.
>
> Was nun - "niemals", oder (negiert) "fast immer"?

du hast das "leicht" überlesen:
man kann immer ohne goto auskommen
und
man kann fast immer leicht ohne goto auskommen

: Bearbeitet durch User
von Jens G. (jensig)


Lesenswert?

gut, ich gebe mich geschlagen ;-)
Aber wenn man lt. Prinzip schwer ohne goto auskommen muß, dann wird's 
wohl vielleicht doch etwas umständlich - oder?
Kommt jedenfalls doch etwas auf den Anwendungsfall an ...

von Joachim B. (jar)


Lesenswert?

Stefan U. schrieb:
> Goto ist ein unnötiges Konstrukt.

informatik student schrieb:
> Goto gibt es nur noch um kompatibel zu altem Code zu
> bleiben. Es gibt aber keinen Grund mehr es zu benutzen.

Joachim B. schrieb:
> hmmm ich habe einen Fall wo ich trotz C goto verwende, vielleicht gehts
> auch anders, ich weiss es nicht.

ist nicht von mir, ist von U.Radig

wie gehts elegant ohne goto?
1
  //Ausgabe der Zeichen
2
  for(;;)
3
  {  by = pgm_read_byte(Buffer++);
4
    if(by==0) break; // end of format string
5
    if (by == '%')
6
    {  by = pgm_read_byte(Buffer++);
7
      if (isdigit(by)>0)
8
      {  str_null_buffer[0] = by;
9
        str_null_buffer[1] = '\0';
10
        move = atoi(str_null_buffer);
11
              by = pgm_read_byte(Buffer++);
12
      }
13
      if(by=='X')
14
        upp=1;
15
      switch (by)
16
      {  case 's':
17
                ptr = va_arg(ap,char *);
18
          while(*ptr) { usart_write_char(*ptr++); }
19
          break;
20
        case 'b':
21
          Base = 2;
22
          goto ConversionLoop;
23
        case 'c':
24
          //Int to char
25
          format_flag = va_arg(ap,int);
26
          usart_write_char (format_flag++);
27
          break;
28
        case 'i':
29
          Base = 10;
30
          goto ConversionLoop;
31
        case 'o':
32
          Base = 8;
33
          goto ConversionLoop;
34
        case 'x':
35
        case 'X':
36
          Base = 16;
37
          //****************************
38
          ConversionLoop:
39
          //****************************
40
          itoa(va_arg(ap,int),str_buffer,Base);
41
          int b=0;
42
          while (str_buffer[b++] != 0){};
43
          b--;
44
          if (b<move)
45
          {  move -=b;
46
            for (tmp = 0;tmp<move;tmp++)
47
              str_null_buffer[tmp] = '0';
48
            //tmp ++;
49
            str_null_buffer[tmp] = '\0';
50
            strcat(str_null_buffer,str_buffer);
51
            strcpy(str_buffer,str_null_buffer);
52
          }
53
          (!upp) ? usart_write_str(str_buffer) : usart_write_str(strupr(str_buffer));
54
          move =0;
55
          break;
56
      }
57
    }  
58
    else
59
      usart_write_char ( by );  
60
  }

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

@Joachim B. (jar)

>wie gehts elegant ohne goto?

Als erstes mal mit weniger Leerzeilen!

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
> Als erstes mal mit weniger Leerzeilen!

wo denn? :)


als ich es merkte korrigiert

passiert immer wenn die Sourcefiles über den Webserver kommen und hier 
per C & P reinkamen, mir ist unklar wo aus 0d 0a die ganzen zusätzlichen 
0a herkommen, ich schmeisse die oft mit hexedit raus, immer sehe ich die 
nicht im Editor

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Etwa so. War echt schwer . . .

von Joachim B. (jar)


Lesenswert?

cool, nur so unwissend ist U.Radig ja nicht, hat er es nicht gesehen 
oder gibts andere Gründe?

Egal es gibt viele Wege nach Rom und später ist man immer schlauer, 
meist jedenfalls.

von Sebastian S. (amateur)


Lesenswert?

Ich würde mein Hirn nehmen.

Schreibe ich einfach so vor mich hin - Spagetti Code - darf ich mich 
nicht wundern, wenn es plötzlich heißt: "Schnell weg hier!"

Praktisch immer handelt es sich um einen - lach nicht - vorhersehbaren 
Fall.

Es gibt aber so viele Kontrollfunktionen, um im Falle eines Falles etwas 
anderes zu machen.
Mit if lässt sich beliebig viel Code ein- bzw. ausblenden.
In Schleifen helfen continue oder break.
In Funktionen hilft auch eventuell ein Einfaches if …. return.
Mittels switch () kann man die Fälle einfach selektieren und alles, was 
nicht passt der else überlassen.

von nichtCler (Gast)


Lesenswert?

Joachim B. schrieb:
> cool, nur so unwissend ist U.Radig ja nicht, hat er es nicht gesehen
> oder gibts andere Gründe?

Er will keine Unterprogramme verwenden?

von Joachim B. (jar)


Lesenswert?

nichtCler schrieb:
> Er will keine Unterprogramme verwenden?

???


war weder vorher ein Unterprogramm und ist auch keines mit Falk seiner 
Lösung, läuft jetzt augenscheinlich gleichwertig und ich gestehe, das 
goto hier war entbehrlich.

: Bearbeitet durch User
von Dummbernd (Gast)


Lesenswert?

Sagt mal Männer,

goto manipuliert doch eigentlich direkt den Programm/Instruktion 
Counter.
Wenn ich also tief in irgendwelchen Unterfunktionen hänge und nun wild 
mit goto rumspringe, dann läuft mir doch irgendwann der heap oder Stack 
über, weil vor dem Aufruf einer Unterfunktion stets relevante Register 
sowie PC gesichert werden?

Erbitte Erleuchtung.

von nichtCler (Gast)


Lesenswert?

Joachim B. schrieb:
> nichtCler schrieb:
>> Er will keine Unterprogramme verwenden?
>
> ???
>
>
> war weder vorher ein Unterprogramm und ist auch keines mit Falk seiner
> Lösung, läuft jetzt augenscheinlich gleichwertig

Warum er Falk seine Lösung nicht genommen hat, weiß ich nicht. Er hätte 
meiner Meinung nach "ConversionLoop" als Unterprogramm deklarieren 
können und überall wo es gebraucht wird aufrufen können, gefolgt von 
einem break im switch-case. Weil er das nicht gemacht hat, dachte ich, 
daß er keine Unterprogramme verwenden möchte. Bin in C nicht so firm. 
Gibt möglicherweise andere Hinderungsgründe mit knappem Speicher, Stack 
oder sonstwas.

von Sebastian S. (amateur)


Lesenswert?

>Erbitte Erleuchtung.

Da ich goto nicht verwende kann ich Dir keine echte Erleuchtung bringen.

Ich glaube aber, irgendwo mal aufgeschnappt zu haben, dass der Compiler 
weiß wo Du bist und demzufolge den Stapel poliert. Das hat natürlich 
seine Grenzen, wenn Du in der Mitte einer Funktion tschüss sagst um 
mitten in einer anderen Sequenz weiterzumachen. Das "Polieren", an der 
Stelle ist wohl nicht das Problem, aber einen passenden Stapel, am Ziel, 
"unterzulegen" wird es wohl sein.

von S. R. (svenska)


Lesenswert?

Dummbernd schrieb:
> Erbitte Erleuchtung.

Aus falschen Annahmen folgt Willkürliches. Was "goto" genau tut, ist in 
der Semantik der Programmiersprache festgeschrieben und im Normallfall 
nicht "ich setze PC einfach auf einen neuen Wert".

In C kann goto nicht in die Mitte einer anderen Funktion springen, wenn 
ich recht informiert bin. Dafür gibt es setjmp/longjmp, die räumen den 
Stack auf. Für den Heap bist du selbst verantwortlich.

von Harry L. (mysth)


Lesenswert?

Joachim B. schrieb:
> cool, nur so unwissend ist U.Radig ja nicht, hat er es nicht gesehen
> oder gibts andere Gründe?

* Pragmatismus ?
* imun gegen "Optimitis"[1] ?

Woher weis der compiler, daß goto verpönt ist?

Fragen über Fragen!

Never touch a running system! ;)


[1] Optimitis: zwanghafter Optimierungswahn

: Bearbeitet durch User
von Sheeva P. (sheevaplug)


Lesenswert?

Peter II schrieb:
> goto bei C (nicht C++) zur Fehlerbehandlung ist üblich und sinnvoll.

Sehr richtig. "goto" ist immer dann sinnvoll, wenn es den Code einfacher 
und übersichtlicher macht, zum Beispiel, wenn man aus verschachtelten 
Schleifen heraus- oder eine Fehlerbehandlung anspringen will. Für 
letzteres kennt C++ eigentlich die Exceptions -- aber wenn man die nicht 
nutzen kann oder will, beispielsweise weil die Limits der Plattform 
(think AVR) keine Exceptions hergeben, kann sogar dort ein "goto" 
sinnvoll sein.

Wichtig ist allerdings, ein paar Regeln einzuhalten, auf die zum Teil 
schon von Sebastian hingewiesen worden ist: nur innerhalb einer 
Funktion, immer nur vorwärts, nach Möglichkeit nicht über mehrere 
Bildschirmseiten springen und den Sprung an beiden Stellen ausführlich 
dokumentieren -- idealerweise mit einer kurzen Begründung.

von Stefan F. (Gast)


Lesenswert?

> wie gehts elegant ohne goto?
> (Codebeispiel)

Dieser Code schreit danach, in mehrere Funktionen aufgesplittet zu 
werden. Allein schon wegen der Übersicht.

Und wenn dann die conversionLoop() als Funktion bereit steht, dann 
kannst du die goto's durch eben diesen Funktionsaufruf ersetzen.

Abgesehen davon: Ich denke schon, dass es sinnvolle Fälle für Goto gibt. 
Aber selten, das ist ein richtiger Exot.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@ Stefan Us (stefanus)

>Dieser Code schreit danach, in mehrere Funktionen aufgesplittet zu
>werden. Allein schon wegen der Übersicht.

Nicht zwingend. Aber der Coding Style ist, naja, verbesserungsfähig.
Wesentliche Kritikpunkte sind.

- goto braucht hier keiner
- Bei if(), for(), while() IMMER Klammern setzen, auch wenn nur eine 
Anweisung drin steht
- ? Operator sehr sparsam einsetzen, wenn er WIRKLICH sinnvoll ist.

>Und wenn dann die conversionLoop() als Funktion bereit steht, dann
>kannst du die goto's durch eben diesen Funktionsaufruf ersetzen.

Braucht man nicht mal.

>Abgesehen davon: Ich denke schon, dass es sinnvolle Fälle für Goto gibt.
>Aber selten, das ist ein richtiger Exot.

EBEN! Aber das haben wir schon dutzendfach festgestellt.

Siehe Anhang. So sieht das DEUTLICH besser aus! Ausserdem war noch ein 
kleiner Fehler drin, upp wurde nicht immer richtig zugewiesen! Auch das 
move = 0 ist weiter oben deutlich sinnvoller platziert.

von W.A. (Gast)


Lesenswert?

Wo braucht man bei strukturierter Programmierung ein "goto"?
https://de.wikipedia.org/wiki/Nassi-Shneiderman-Diagramm

Das C da einige Altlasten in Form von "break", "continue" und "goto" 
mitschleppt, ist wohl der historischen Entwicklung geschuldet.

von Rolf M. (rmagnus)


Lesenswert?

W.A. schrieb:
> Wo braucht man bei strukturierter Programmierung ein "goto"?

Es geht nicht darum, ob man es braucht, sondern darum, ob es Fälle gibt, 
in denen der Code dadurch übersichtlicher wird.
Schließlich braucht man ziemlich viel nicht. Man braucht z.B. auch keine 
Datentypen, wenn man wie in Assembler einfach immer die Instruktion 
nutzt, die die Daten eben passend interpretiert.
Nun machen Datentypen den Code praktisch immer übersichtlicher. Bei goto 
gibt's nur wenige Fälle, aber es gibt sie.

> Das C da einige Altlasten in Form von "break", "continue" und "goto"
> mitschleppt, ist wohl der historischen Entwicklung geschuldet.

Was für eine historische Entwicklung meinst du? Was ist denn in den 
letzten 25 Jahren in C dazugekommen, das irgendwas an der Nützlichkeit 
dieser Teile geändert hätte?

von W.A. (Gast)


Lesenswert?

Rolf M. schrieb:
> Was für eine historische Entwicklung meinst du?

Den verstärkten Trend zu strukturierter Programmierung.

> Was ist denn in den letzten 25 Jahren in C dazugekommen, das irgendwas an
> der Nützlichkeit dieser Teile geändert hätte?

Welche Nützlichkeit meinst du?

Und wie kommst du gerade auf 25 Jahre? Das Kind von Brian W. Kernighan 
und Dennis M. Ritchie lebt seit mittlerweile 38 Jahren.

Jeder C-Block im Sinne der strukturierten Programmierung ist ein 
einzelnes Statement oder ein durch "{"..."}" zusammengefasste Gruppe von 
Statements. Eine select()-case struktur mit ihrem break tanzt da 
kräftig aus der Reihe. Bei strukturierter Programmierung mit 
Funktionsblöcken, die genau einen definierten Eingang und Ausgang 
haben ist jede Form von goto (goto, break, continue) kontraproduktiv.

So ein Bedürfniss nach einem Hinterausgang entspringt wohl eher der 
Programmiererbequemlichkeit als dem Wunsch nach sauberer 
Programmstruktur.

von Falk B. (falk)


Lesenswert?

@ W.A. (Gast)

>Statements. Eine select()-case struktur mit ihrem break tanzt da
>kräftig aus der Reihe.

Jain. Das C-switch ist auf break prinzipiell angewiesen, weil man jeden 
Zweig damit abschließen muss, wenn man nicht absichtlich in den nächsten 
reinfallen will. In Pascal, BASIC etc. braucht man das nicht, dort sind 
die Zweige von vorn herein nicht "durchfallend".

> Bei strukturierter Programmierung mit
>Funktionsblöcken, die genau einen definierten Eingang und Ausgang
>haben ist jede Form von goto (goto, break, continue) kontraproduktiv.

Hmmm, jain. Ein break und continue ist in einer for/while Schleife hin 
und wieder ganz praktisch, auch ohne Spaghetticode zu produzieren. Auch 
mehrfache return in Funktionen sind bisweilen sinnvoll und praktisch und 
beeinträchtigen die Codequalität nicht negativ.

>So ein Bedürfniss nach einem Hinterausgang entspringt wohl eher der
>Programmiererbequemlichkeit als dem Wunsch nach sauberer
>Programmstruktur.

C ist nicht perfekt, aber in der Praxis nun mal sehr breit etabliert. So 
wie Windows, Verbrennungsmotoren und Schulzeugnisse ;-)

von Joachim B. (jar)


Lesenswert?

Ich bin ja nun kein Progger (obwohl ich programmiere)

aber wenn ich jede Funktion auf korrekte Funktion überprüfe gibt es 
viele Fehlerfälle. Wenn ich diese in Verzweigungen einrücke finde ich 
die Verschachtelungstiefe sehr hoch was irgendwan den Code auch 
unübersichtlich in meinen Augen macht.

So ein goto error; kann da helfen.

Ich hatte in div. Kursen auch gelernt nicht mehrere Aussprungpunkte zu 
machen

also Funktion Eingang -> ein Funktion Ausgang.

solche Konstrukte wie
funk()
{
if a=b return;
if a=c return;
if c!=b return;

return;
}

sollten vermieden werden (ich weiss schlechtes Beispiel kann grad nicht 
besser, stellt euch das in großem Code vor)

da denke ich das hier wäre eben besser

funk()
{
if a=b goto raus;
if a=c goto raus;
if c!=b goto raus;

// hier ist noch was;

raus:
return;
}

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Rolf M. schrieb:
> Man braucht z.B. auch keine
> Datentypen, wenn man wie in Assembler einfach immer die Instruktion
> nutzt, die die Daten eben passend interpretiert.

Naja, ob du das nun implizit (in Assembler) oder explizit (in einer 
Hochsprache) deklarierst: Dennnoch ist und bleibt es ein ein 
Daten-Objekt mit einem zugehörigen Datentyp! Ob du dir das nun auf einem 
Blatt Papier aufschreibst, dir im Kopf merkst oder dediziert 
deklarierst, ist dabei egal.

Du solltest schon den Überblick haben und zu jedem Zeitpunkt "wissen", 
wie dein zu bearbeitendes Datenobjekt "aufgebaut" ist, und welche 
Operationen du darauf anwenden kannst.

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Joachim B. schrieb:
> da denke ich das hier wäre eben besser
>
> funk()
> {
> if a=b goto raus;
> if a=c goto raus;
> if c!=b goto raus;
>
> // hier ist noch was;
>
> raus:
> return;
> }

Dafür gibt es Switch-Case Anweisungen. Schonmal ausprobiert?
http://www.c-howto.de/tutorial-verzweigungen-switch-case.html

von W.A. (Gast)


Lesenswert?

Falk B. schrieb:
> Das C-switch ist auf break prinzipiell angewiesen, weil man jeden
> Zweig damit abschließen muss, wenn man nicht absichtlich in den nächsten
> reinfallen will.

Das sag ich ja.

Warum ist im Sprachstandard nicht festgelegt, dass hinter jedem case 
genau ein Statement/{..} folgt und fertig. Wegen dieser Inkonsequenz 
meine ich, dass die C-switch Struktur ein Relikt aus Zeiten vor der 
konsequenten strukturierten Programmierung ist und dass das break ein 
(verstecktes) Goto über einen Hinterausgang darstellt.

von Paul B. (paul_baumann)


Lesenswert?

Wenn es statt "Goto" "HUPF" hieße, würden sich die Leute auch nicht so 
gegen seine Verwendung sträuben.

MfG Paul

von Joachim B. (jar)


Lesenswert?

Wegstaben V. schrieb:
> Dafür gibt es Switch-Case Anweisungen.

nicht verstanden?

Joachim B. schrieb:
> (ich weiss schlechtes Beispiel kann grad nicht
> besser, stellt euch das in großem Code vor)

Wegstaben V. schrieb:
> Dafür gibt es Switch-Case Anweisungen. Schonmal ausprobiert?
> http://www.c-howto.de/tutorial-verzweigungen-switch-case.html

ne nicht "ausprobiert" sondern nutze ich oft!

Ich habe einmal selber goto genutzt, nach dem wakeup in einer sleep Funk 
wieder an den Anfang zu springen, wie sonst?

init-teil

einiges was nur einmal gemacht wird.

neustart:
anderes was nach jedem Neustart gemacht wird.


while(1)
{

viel code

//hier gings mal in den sleep
if wakeup goto neustart;

}

von The D. (thedaz)


Lesenswert?

Mag sein, daß goto in der C-Welt seine Berechtigung hat. In der C++ Welt 
braucht man es defakto nicht und falls ich jemals gefragt werden sollte 
(was nicht passieren wird), würde ich für die Löschung aus dem Standard 
stimmen. Das gleiche gilt für die Möglichkeit im switch das break 
wegzulassen. In meiner Erfahrung ist das bisher immer ein Fehler 
gewesen. Resourcen-Handling erledigt man automatisch mit RAII (nicht das 
aus der Tube).

von nanana (Gast)


Lesenswert?

Mal ne Frage: wie würdet ihr ein 'intervall' switch-case implementieren? 
Also falls x in[0,1] tue das, falls in [2,3[ dies, sonst jenes. Als 
'endlosen' if-else Baum?
Oder wäre das u.U mit goto und einer Kommentarzeile eleganter?

von Helmut L. (helmi1)


Lesenswert?

Paul B. schrieb:
> Wenn es statt "Goto" "HUPF" hieße, würden sich die Leute auch nicht so
> gegen seine Verwendung sträuben.

Ist das die bayerische C Version?

switch = I_WOAS_NET

while = MOACH_WOAS
.
.
..

von Axel S. (a-za-z0-9)


Lesenswert?

W.A. schrieb:
> Warum ist im Sprachstandard nicht festgelegt, dass hinter jedem case
> genau ein Statement/{..} folgt und fertig.

Weil es dann die Möglichkeit des fall through nicht gäbe. Aber genau 
die wollten Kernigham und Ritchie anscheinend haben. Und oft ist sie 
auch ganz praktisch. Z.B. immer dann wenn zwei (oder mehr) Fälle zu 
exakt dem gleichen Code führen sollen.

von Freddy (Gast)


Lesenswert?

Amüsante Diskussion.

Hatten wir schon vor 40 Jahren: Gleiche Argumente gleiche Borniertheit.

Niklaus Wirth baute damals seinen Pascal-Compiler natürlich ohne goto.

Nicht ganz.

Es gab doch eins, um aus einem völlig verwursteten Syntaxzweig 
herauszukommen. Heute nimmt man dafür Excepions.

Niklaus Wirt:
Äquivalenz der Struktur von Daten und Programm.

Dem goto entspricht die Adresse also Pointer in C

PS.

Für Duden-Paule (pow):

Scheunen Sonndach ook

von Rolf M. (rmagnus)


Lesenswert?

The D. schrieb:
> Mag sein, daß goto in der C-Welt seine Berechtigung hat. In der C++ Welt
> braucht man es defakto nicht und falls ich jemals gefragt werden sollte
> (was nicht passieren wird), würde ich für die Löschung aus dem Standard
> stimmen. Das gleiche gilt für die Möglichkeit im switch das break
> wegzulassen. In meiner Erfahrung ist das bisher immer ein Fehler
> gewesen.

Ich habe das durchaus schon mit Absicht benutzt, weil Alternativen immer 
irgendwie umständlicher gewesen wären. Natürlich hab ich einen 
entsprechenden Kommentar dazugeschrieben. Ich scheue mich nicht, sowas 
in Fällen, wo es sinnvoll ist, auch zu verwenden. Sich dann irgendeine 
umständliche und komplizierte Alternative einfallen zu lassen, nur weil 
irgendwer behauptet, die in diesem Fall einfachste Lösung sei 
grundsätzlich böse, finde ich albern.

> Resourcen-Handling erledigt man automatisch mit RAII (nicht das
> aus der Tube).

Ich hab nie begriffen, warum das so heißt, aber ja, in C++ tut man das.

nanana schrieb:
> Mal ne Frage: wie würdet ihr ein 'intervall' switch-case implementieren?
> Also falls x in[0,1] tue das, falls in [2,3[ dies, sonst jenes. Als
> 'endlosen' if-else Baum?
> Oder wäre das u.U mit goto und einer Kommentarzeile eleganter?

Entweder - wenn das eine Option ist - entsprechende 
Compiler-Erweiterungen nutzen (gcc kann z.B. switch/case auch mit 
Wertebereichen), oder eben mit einer Reihe if/else (was ich in diesem 
Fall bevorzugen würde). Warum sollte man dafür goto nutzen?

von Falk B. (falk)


Lesenswert?

@ Rolf Magnus (rmagnus)

>Compiler-Erweiterungen nutzen (gcc kann z.B. switch/case auch mit
>Wertebereichen),

Ist nicht portabel.

> oder eben mit einer Reihe if/else (was ich in diesem
>Fall bevorzugen würde). Warum sollte man dafür goto nutzen?

Weil der Drang zum Frickeln bei einigen Menschen überaus hoch ist ;-)
(auch bei bezahlten Profis)

von Dussel (Gast)


Lesenswert?

Warum hängen in Bussen immer diese roten Hämmerchen? Ich kennen 
niemanden, der eins davon mal benutzt hätte. Ist das also nur auf den 
Einfluss der Nothammerlobby zurückzuführen?
Goto ist der Nothammer der imperativen Programmierung.

von Rolf M. (rmagnus)


Lesenswert?

Falk B. schrieb:
> @ Rolf Magnus (rmagnus)
>
>>Compiler-Erweiterungen nutzen (gcc kann z.B. switch/case auch mit
>>Wertebereichen),
>
> Ist nicht portabel.

Deshalb bevorzuge ich ja die Version mit if/else. Wobei ich sagen muss, 
dass ich schon ziemlich lange kein C-Programm mehr geschrieben habe, das 
auf was anderem als gcc übersetzt wurde. Dennoch tendiere ich dazu, 
compilerspezifische Erweiterungen zu meiden.

von Heinz L. (ducttape)


Lesenswert?

Third E. schrieb:
> Mir fällt ein spezieller Fall ein, wo goto bei Error Handling
> tatsächlich Sinn macht:
> Man könnte zwar den Aufräum-Code in eine separate Funktion packen, wie
> im Code von Heinz L.. Dies hat aber zusätzliche Funktionsaufrufe zur
> Folge, was Ausführungszeit und Kompilatgröße betrifft. Zumindest, wenn
> der Aufräumcode von mehreren Stellen aus aufgerufen wird.
> Ich habe mal einen Fall mitbekommen, wo es auf jedes eingesparte
> Flash-Byte ankam. Wegen sehr großer verbauter Stückzahl war es nicht
> möglich, einfach den nächstgrößeren µC zu verwenden.

Wenn's wirklich um jedes Byte Flash geht würd ich zuerst mal hergehen 
und ein paar simple Routinen in ASM umsetzen. Damit gewinnt man 
(angesichts der idiotisch miesen Optimierung des AVR-Compilers) mehr.

von Joachim B. (jar)


Lesenswert?

Heinz L. schrieb:
> in ASM umsetzen. Damit gewinnt man
> (angesichts der idiotisch miesen Optimierung des AVR-Compilers) mehr.

ist das so? hier meinen aber einige assembler Spezis anderes, so 
schlecht soll der gcc nicht mehr sein!

Ich selber staune immer wie gut der gcc optimiert mit -0s

Selbst wenn ich denke ich könnte den Code verbessern/verkürzen indem ich 
ihn verändere (2 Byte Flash Text optimiert gespart), logisch wurde der 
kürzer, aber die Optimierung ist dann schlechter, aus 2 Byte - wird im 
Code +6 bis +10 Byte.

von Thomas E. (picalic)


Lesenswert?

Joachim B. schrieb:
> ist das so? hier meinen aber einige assembler Spezis anderes, so
> schlecht soll der gcc nicht mehr sein!

Schlecht ist er sicher nicht, aber in Assembler kann man oft doch noch 
etwas optimieren. Ich habe mal den AES-Bootloader (AVR231) für ein 
Projekt benutzt, allerdings musste wg. Kompatibilität zu anderen Geräten 
da noch ein spezielles Kommunikations-Protokoll drübergelegt werden. 
Ohne Ersatz einiger AES-Funktionen durch ASM-Routinen hätte ich keine 
Chance gehabt, den BL in 1K Words unterzubringen. Nun bin ich nichtmal 
so der AVR-Crack, d.h. AVR-Assembler war eher Fremdsprache (bisschen 
anders, als PIC eben...), trotzdem hats am Ende doch schon viel 
gebracht.
Also, besser, als ein mittelmäßiger ASM-Programmierer ist der GCC auch 
nicht!

von Falk B. (falk)


Lesenswert?

@Joachim B. (jar)


>Heinz L. schrieb:
>> in ASM umsetzen. Damit gewinnt man
>> (angesichts der idiotisch miesen Optimierung des AVR-Compilers) mehr.

>ist das so?

Nein. Das ist nur die Meinung eines gesicht, namens- und ahnungslosen 
Heinz.
Das ist modern . . .

>Ich selber staune immer wie gut der gcc optimiert mit -0s

Das tut er.

von Falk B. (falk)


Lesenswert?

@ Thomas Elger (picalic)

>Schlecht ist er sicher nicht, aber in Assembler kann man oft doch noch
>etwas optimieren.

Was aber in denn allerwenigsten Fällen wirklich sinnvoll und notwendig 
ist!

>Ohne Ersatz einiger AES-Funktionen durch ASM-Routinen hätte ich keine
>Chance gehabt, den BL in 1K Words unterzubringen.

Das ist so ein Ausnahmefall.

von Joachim B. (jar)


Lesenswert?

Falk B. schrieb:
>>Ich selber staune immer wie gut der gcc optimiert mit -0s
>
> Das tut er.

danke Falk!

von Frank B. (f-baer)


Lesenswert?

Joachim B. schrieb:
> solche Konstrukte wie
> funk()
> {
> if a=b return;
> if a=c return;
> if c!=b return;
>
> return;
> }

Das Zauberwort heisst in diesem Fall "else if".


Ich habe in den letzten Jahren genau an einer Stelle GOTO eingesetzt, 
und bin nach wie vor davon überzeugt, dass das eine der wenigen 
Anwendungen war, wo es die Lesbarkeit des Codes deutlich erhöht und 
gleichzeitig deutlich schneller ist:
1
if(z_measurement_g)
2
    {
3
      if(Z1_g.motion_ctrl.mode_active == mode_z_measurement)
4
        goto Z1_measurement;
5
      if(Z2_g.motion_ctrl.mode_active == mode_z_measurement)
6
        goto Z2_measurement;      
7
      if(Z3_g.motion_ctrl.mode_active == mode_z_measurement)
8
        goto Z3_measurement;  
9
      if(Z4_g.motion_ctrl.mode_active == mode_z_measurement)
10
        goto Z4_measurement;  
11
      if(Z5_g.motion_ctrl.mode_active == mode_z_measurement)
12
        goto Z5_measurement;  
13
      if(Z6_g.motion_ctrl.mode_active == mode_z_measurement)
14
        goto Z6_measurement;  
15
      if(Z7_g.motion_ctrl.mode_active == mode_z_measurement)
16
        goto Z7_measurement;  
17
    }
18
    
19
Z1_measurement:
20
    stepper_handle(&Z1_g);    
21
    if(z_measurement_g)
22
      continue;  
23
Z2_measurement:
24
    stepper_handle(&Z2_g);
25
    if(z_measurement_g)    
26
      continue;    
27
Z3_measurement:    
28
    stepper_handle(&Z3_g);
29
    if(z_measurement_g)    
30
      continue;  
31
Z4_measurement:
32
    stepper_handle(&Z4_g);
33
    if(z_measurement_g)    
34
      continue;    
35
Z5_measurement:    
36
    stepper_handle(&Z5_g);
37
    if(z_measurement_g)    
38
      continue;  
39
Z6_measurement:    
40
    stepper_handle(&Z6_g);
41
    if(z_measurement_g)    
42
      continue;  
43
Z7_measurement:    
44
    stepper_handle(&Z7_g);
45
    if(z_measurement_g)    
46
      continue;

Der Code stammt aus einer Mehrachs-Schrittmotor-Steuerung, bei der es 
einen zeitkritischen Vermessungsmodus gibt. Wenn auf einer Achse die 
Vermessung aktiv ist, wird die Bearbeitung der anderen Achsen 
übersprungen.
z_measurement_g wird beim Starten der Vermessung gesetzt, um die anderen 
Achsen zu blockieren.
Da ich grundsätzlich kein großer Freund von GOTO bin, habe ich mir 
damals über Alternativen lange Gedanken gemacht.
- Organisation der Datenstrukturen Zn_g in einem Array
- Measurement-Modes für alle Achsen bitweise in eine gemeinsame Variable 
mappen mit der man dann weiter arbeiten kann

Array: Der Implementierungsaufwand dafür wäre enorm gewesen, weil das 
Feature erst später kam. Aber auch mit dem Array lässt sich das nicht 
deutlich besser UND lesbar abbilden.
Mapping in gemeinsame Variable: Verschlechtert die Lesbarkeit des Codes 
enorm, da dieses Mapping NUR für den Vermessungsmodus, aber nicht für 
Fahrmodi, Initialisierungen o.ä. verwendet wird.
Die letzte Alternative wäre vor der Verarbeitung jeder Achse einen 
if-Block mit 7 Bedingungen zu setzen, der meine Ansprüche an Lesbarkeit 
überhaupt nicht erfüllt.

von MCUA (Gast)


Lesenswert?

>Man springt auch nicht aus Prozeduren und Funktionen mit GOTO raus um
>irgendwo anders hinzukommen,.....
das sollte inner Hochsprache eigentlich gar nicht möglich sein

von Thomas (Gast)


Lesenswert?

GOTO zu verpönen hat schon etwas wie eine Glaubensfrage an sich.

Sicher lässt sich mit GOTOs ein absolut unverständlicher Spinnennetzcode 
erzeugen. Das muss aber nicht so sein (siehe das Beispiel darüber).
Alle Programmzweige mit if.. then..else abzubilden kann sehr unlesbar 
werden.

Strukturierte Programmierung fordert Blöcke mit einem Eingang und einem 
Ausgang. Wenn ein GOTO zum Ende des Blocks springt, dann habe auch keine 
Regelverletzung.

Bei sehr begrenzten Ressourcen kann hier durchaus eine Code-Einsparung 
erzielt werden und der Code wird besser lesbar und damit besser wartbar.
Uns haben derartige Einsparungen schon mehrmals den Kopf gerettet.

Wie eingangs erwähnt ist es eigentlich wieder eine der Glaubensfragen. 
Es wird immer Fanatiker für beide Richtungen geben. Mit Hirn verwendet 
können GOTOs durchaus sinnvoll sein.

Thomas

von Oliver S. (oliverso)


Lesenswert?

Thomas schrieb:
> Mit Hirn verwendet
> können GOTOs durchaus sinnvoll sein.

Natürlich. Es gibt Anwendungen, bei denen es tatsächlich sinnvoll ist.

Bei der Fragestellung des TO:

Paul schrieb:
> void hat aber die Eigenschaft, dort weiter zu machen, von wo es
> aufgerufen wurde, es kehrt also zurück.
> Wenn ich goto nutze, ergibt es teilweise eine totale
> Unübersichtlichkeit.

ist die einzige richtige Antwort dann aber doch:

Kein goto verwenden. NIEMALS.

Oliver

von Joachim B. (jar)


Lesenswert?

Oliver S. schrieb:
> Thomas schrieb:
>> Mit Hirn verwendet
>> können GOTOs durchaus sinnvoll sein.
>
> Natürlich. Es gibt Anwendungen, bei denen es tatsächlich sinnvoll ist.

da fällt mir mein relokatibler Code am PC1500 ein, hatte ich zwar in 
Assembler gemacht aber auch JMP genauer branch (goto) benutzt.

Ich wollte ja eine Unteroutine aufrufen von verschiedenen Stellen.

Dummerweise ging jump subroutine oder jmp nicht weil das der Assembler 
in absolute Adressen umsetzt und so relokatibler Code nicht 
gewährleistet ist.

Ergo habe ich im PC Register geschaut gesichert das auf den Stack mit 
Korrektur geschrieben und mit +branch vorwärts oder -branch rückwärts 
(goto) hingehüpft, mit rts konnte ich immer wieder an die richtige 
Stelle zurück egal wo sie im Speicher lag.

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


Lesenswert?

Frank B. schrieb:
> Der Code stammt aus einer Mehrachs-Schrittmotor-Steuerung, bei der es
> einen zeitkritischen Vermessungsmodus gibt. Wenn auf einer Achse die
> Vermessung aktiv ist, wird die Bearbeitung der anderen Achsen
> übersprungen.
> z_measurement_g wird beim Starten der Vermessung gesetzt, um die anderen
> Achsen zu blockieren.
> Da ich grundsätzlich kein großer Freund von GOTO bin, habe ich mir
> damals über Alternativen lange Gedanken gemacht.
> - Organisation der Datenstrukturen Zn_g in einem Array
> - Measurement-Modes für alle Achsen bitweise in eine gemeinsame Variable
> mappen mit der man dann weiter arbeiten kann

Also,

die Variable z_measurement_g einzuführen ist okay, aber die bevorzugte 
Achse so zu speichern nicht?

zu deinem Code:

ich hab dein struct mal motion genannt (keine Ahnung wie es heist) und 
es ist als typedef angelegt. Deswegen keine structs im code.

ohne goto und schön übersichtlich. Auf Kosten von 7 Zeigern.
1
motion allAxes[]{ Z1_g, Z2_g, Z3_g, Z4_g, Z5_gZ6_g, Z7_g };
2
3
if (z_measurement_g) {
4
  motion *priorRankedAxis = findPriorRankedAxis(allAxes,sizeof(allAxes));
5
       if (priorRankedAxis != NULL){
6
    stepper_handle(priorRankedAxis);
7
  }
8
}
9
else{
10
  for (int i = 0; i < sizeof(allAxes); i++) {
11
    stepper_handle(&allAxes[i]);
12
  }
13
}

mit
1
motion* findPriorRankedAxis(motion *allAxes, int count) {
2
  for (int i = 0; i < count; i++) {
3
    if (allAxes[i].motion_ctrl.mode_active) {  
4
      return &allAxes[i];
5
    }
6
  }
7
  return NULL;  
8
}

PS: wer fehler findet darf sie gerne aufzeigen ohne Flamen. Ich 
programmier so selten C da können kleinigkeiten schon mal durchrutschen. 
Bei den sizeof Geschichten bin ich mit nicht sicher ob das so richtig 
ist.

von Entsetzter (Gast)


Lesenswert?

Frank B. schrieb:

> Ich habe in den letzten Jahren genau an einer Stelle GOTO eingesetzt,
> und bin nach wie vor davon überzeugt, dass das eine der wenigen
> Anwendungen war, wo es die Lesbarkeit des Codes deutlich erhöht und
> gleichzeitig deutlich schneller ist:

   [Ganz viel schlimmer Mist gelöscht]

Man, Leute, lernt mal wieder einfache, boolsche Logik, dann muss man 
auch keine Goto- und continue-Wüsten schreiben. Nichts für ungut, aber 
dieses Beispiel ist wirklich als Negativ-Beispiel für ein Lehrbuch 
geeignet.

Und nun die Lösung: Punkt eins ist immer, sich selbst zu verstehen was 
man will. Was willst Du mit Deinem Code?

 a.) Wenn z_measurement_g == FALSE ist, alle Schrittmotoren aufrufen.
 b.) Wenn z_measurement_g == TRUE ist, nur einen bestimmten.

Also, ganz einfach:

1
  if (!z_measurement_g || Z1_g.motion_ctrl.mode_active == mode_z_measurement)
2
    stepper_handle(&Z1_g);
3
4
  if (!z_measurement_g || Z2_g.motion_ctrl.mode_active == mode_z_measurement)
5
    stepper_handle(&Z2_g);
6
7
  if (!z_measurement_g || Z3_g.motion_ctrl.mode_active == mode_z_measurement)
8
    stepper_handle(&Z3_g);
9
10
  if (!z_measurement_g || Z4_g.motion_ctrl.mode_active == mode_z_measurement)
11
    stepper_handle(&Z4_g);
12
13
  if (!z_measurement_g || Z5_g.motion_ctrl.mode_active == mode_z_measurement)
14
    stepper_handle(&Z5_g);
15
16
  if (!z_measurement_g || Z6_g.motion_ctrl.mode_active == mode_z_measurement)
17
    stepper_handle(&Z6_g);
18
19
  if (!z_measurement_g || Z7_g.motion_ctrl.mode_active == mode_z_measurement)
20
    stepper_handle(&Z7_g);

Und wenn Du dass noch Z1_g bis Z7_g in ein Array wandelst, verfällt 
dieser GOTO-Continue-Wahnsinn in eine einfache Schleife aus vier Zeilen!

von nicht"Gast" (Gast)


Lesenswert?

Oh je, das war natürlich Blödsinn mit dem Zeiger. Es werden im Code 
drüber natürlich Kopien angelegt.

Der Code geht natürlich auch, aber hier noch mal die Änderung mit 
Zeigern:
1
motion *allAxes[]{ &Z1_g, &Z2_g, &Z3_g, &Z4_g, &Z5_g, &Z6_g, &Z7_g };
2
int axesCount = sizeof(allAxes) / sizeof(*allAxes);
3
4
if (z_measurement_g) {
5
  motion *priorRankedAxis = findPriorRankedAxis(allAxes, axesCount);
6
  if (priorRankedAxis != NULL) {
7
    stepper_handle(priorRankedAxis);
8
  }
9
}
10
else {
11
  for (int i = 0; i < axesCount; i++) {
12
    stepper_handle(allAxes[i]);
13
  }
14
}

mit
1
motion* findPriorRankedAxis(motion **allAxes, int count) {
2
  for (int i = 0; i < count; i++) {
3
    if (allAxes[i]->motion_ctrl.mode_active) {
4
      printf("gefunden %d\n", i);
5
      return allAxes[i];
6
    }
7
  }
8
  return NULL;
9
}

von Paul B. (paul_baumann)


Lesenswert?

nicht"Gast" schrieb:
> Oh je, das war natürlich Blödsinn mit dem Zeiger.

Das hat ja nicht lange gedauert, bis das jemand auf den Zeiger ging

MfG Paul

von W.S. (Gast)


Lesenswert?

Paul schrieb:
> Wenn ich goto nutze, ergibt es teilweise eine totale
> Unübersichtlichkeit. Ist schlecht nachzuvollziehen wo es weiter geht.
> Im Netz wird da von gesprochen, das es verpöönt ist nichrr genutzt
> werden soll.
> Was nutz ihr bei solchen Sachen?

Eigentlich ist es ja so unsäglich EINFACH: Anstatt sich in Situationen, 
wo ein simples GOTO angesagt ist, um irgendwelche krummen 
Ersatz-Ausdrücke zu bemühen, nimmt man schlichtweg ein Goto und gut ist 
es.

Üble Beispiele aus der Welt der C-Programmiere sind sowas:
for (;;;) blabla...;
while (1) blabla...;

Das sind alles entartete Konstrukte, weil sie eigentlich für ganz andere 
Einsatzfälle in die Sprache aufgenommen wurden und hier eben nur durch 
leider nicht unzulässige Parameter vergewaltigt wurden. Für solche Fälle 
ist das Setzen einer Merke und GOTO die sauberste, einfachste, lesbarste 
und stilvollste Methode.

Historisch war das verpönen von GOTO einfach nur dem Umstand geschuldet, 
daß die allermeisten Hobby-Programmierer an das damalige BASIC gewöhnt 
waren, wo GOTO schlichtweg unerläßlich war, da das damalige BASIC streng 
zeilennummerorientiert war. Ich sehe da Parallelen zur menschlichen 
Gesellschaft in prähistorischen Zeiten, wo nomadisierende Völkerstämme 
Verpön-Regeln aufgestellt hatten, um eine Verbrüderung mit 
ortsansässigen Bauern zu verhindern. Und dreitausend Jahre später labern 
deren Nachfahren immer noch dieselben inzwischen obsolet gewordenen 
Regeln daher - aus schierem Unverständnis.

Beim Lesen deines Eröffnungs-Posts beschleicht mich jedoch der Gedanke, 
daß du versuchst, per Goto von einer Funktion in eine andere zu springen 
- und das wäre dann wirklich ganz schlechter Code, falls überhaupt 
zulässig.

W.S.

von Dussel (Gast)


Lesenswert?

W.S. schrieb:
> Üble Beispiele aus der Welt der C-Programmiere sind sowas:
> for (;;;) blabla...;
> while (1) blabla...;
>
> Das sind alles entartete Konstrukte, weil sie eigentlich für ganz andere
> Einsatzfälle in die Sprache aufgenommen wurden und hier eben nur durch
> leider nicht unzulässige Parameter vergewaltigt wurden. Für solche Fälle
> ist das Setzen einer Merke und GOTO die sauberste, einfachste, lesbarste
> und stilvollste Methode.
Der Beitrag kommt vier Tage zu spät. Gut ist er aber trotzdem. :D

von Rüdiger (Gast)


Lesenswert?

W.S. schrieb:
> Üble Beispiele aus der Welt der C-Programmiere sind sowas:
> for (;;;) blabla...;
> while (1) blabla...;

Mein Favorit ist ja noch immer:
while("my guitar gently weeps") ...


Aber auch eine Endlosschleife ist noch immer eine Schleife.
Den C-Kontrollstrukturen sieht man (sofern man es nicht sehr drauf 
anlegt...) auf den ersten Blick an was sie machen und wo es weitergeht 
und die Verzweigungen ergeben sich direkt aus dem lokalen Kontext.

Bei einem goto weiß man nur, dass es irgendwo anders weitergeht, das 
Label könnte aber sonstwo stehen.


> Für solche Fälle ist das Setzen einer Merke und GOTO die sauberste, einfachste, 
lesbarste und stilvollste Methode.

Ich bin ja dafür es rekursiv zu lösen, funktionale Programmierung ist 
immerhin recht elegant und mit Endrekursion macht auch eine 
Endlosschleife keine Probleme...

von Bernd K. (prof7bit)


Lesenswert?

Rüdiger schrieb:
> Mein Favorit ist ja noch immer:
> while("my guitar gently weeps")

Optimiert er den String weg? Bin jetzt zu faul ums auszuprobieren.

von Rolf M. (rmagnus)


Lesenswert?

W.A. schrieb:
> Welche Nützlichkeit meinst du?

Die, von der du behauptest, sie sei aufgrund "historischer Entwicklung" 
nicht mehr gegeben.

> Und wie kommst du gerade auf 25 Jahre?

Kein spezieller Grund. Ein viertel Jahrhundert schien mir nur lang 
genug. Es ist auch ungefähr die Zeit, seit der C genormt ist.

> Bei strukturierter Programmierung mit Funktionsblöcken, die genau einen
> definierten Eingang und Ausgang haben ist jede Form von goto (goto,
> break, continue) kontraproduktiv.

Mangels eines besseren Konstrukts kann es aber trotzdem sinnvoll sein.

Wegstaben V. schrieb:
> Rolf M. schrieb:
>> Man braucht z.B. auch keine
>> Datentypen, wenn man wie in Assembler einfach immer die Instruktion
>> nutzt, die die Daten eben passend interpretiert.
>
> Naja, ob du das nun implizit (in Assembler) oder explizit (in einer
> Hochsprache) deklarierst: Dennnoch ist und bleibt es ein ein
> Daten-Objekt mit einem zugehörigen Datentyp!

Es geht hier um in Programmiersprachen eingebaute Konzepte, nicht darum, 
was ich implizit noch so außenrum mache.

> Ob du dir das nun auf einem Blatt Papier aufschreibst, dir im Kopf merkst
> oder dediziert deklarierst, ist dabei egal.

Egal? Naja, also ich find's schon ziemlich praktisch, dass dieses 
Konzept in der Sprache integriert ist und ich mir die Typen nicht extra 
auf einem Blatt Papier aufschreiben muss. Und dass der Compiler die 
Chance hat, da auch drüber zu schauen.

W.S. schrieb:
> Üble Beispiele aus der Welt der C-Programmiere sind sowas:
> for (;;;) blabla...;
> while (1) blabla...;
>
> Das sind alles entartete Konstrukte, weil sie eigentlich für ganz andere
> Einsatzfälle in die Sprache aufgenommen wurden und hier eben nur durch
> leider nicht unzulässige Parameter vergewaltigt wurden.

Dann erkläre mal, warum for so definiert ist, dass man die Bedingung 
weglassen kann, wenn nicht genau, um eine Schleife ohne diese machen zu 
können.

> Für solche Fälle ist das Setzen einer Merke und GOTO die sauberste,
> einfachste, lesbarste und stilvollste Methode.

Was soll daran besser sein als es als das zu definieren, was es ist: 
Eine Schleife?

> Historisch war das verpönen von GOTO einfach nur dem Umstand geschuldet,
> daß die allermeisten Hobby-Programmierer an das damalige BASIC gewöhnt
> waren, wo GOTO schlichtweg unerläßlich war, da das damalige BASIC streng
> zeilennummerorientiert war.

Ich glaube, umgekehrt wird ein Schuh draus: Dass es goto in C überhaupt 
gibt, ist den genannten Umständen geschuldet.

von W.S. (Gast)


Lesenswert?

Rolf M. schrieb:
> Dann erkläre mal, warum for so definiert ist, dass man die Bedingung
> weglassen kann, wenn nicht genau, um eine Schleife ohne diese machen zu
> können.

Nun, man hat gerade in C durchaus die große Freiheit sich daneben zu 
benehmen, aber auch dann, wenn es nicht explizit verboten ist, sich 
selbst in die Suppe zu spucken oder andern Leuten auf den Türvorleger zu 
scheißen - so gilt dies unter zivilisierten Leuten als eher 
unschicklich, gelle?

W.S.

von S. R. (svenska)


Lesenswert?

W.S. schrieb:
> Nun, man hat gerade in C durchaus die große Freiheit sich daneben zu
> benehmen, aber auch dann, wenn es nicht explizit verboten ist, sich
> selbst in die Suppe zu spucken oder andern Leuten auf den Türvorleger zu
> scheißen - so gilt dies unter zivilisierten Leuten als eher
> unschicklich, gelle?

Wie auch goto. ;-)

von Sheeva P. (sheevaplug)


Lesenswert?

Heinz L. schrieb:
> Wenn's wirklich um jedes Byte Flash geht würd ich zuerst mal hergehen
> und ein paar simple Routinen in ASM umsetzen. Damit gewinnt man
> (angesichts der idiotisch miesen Optimierung des AVR-Compilers) mehr.

Wie Yalu bereits in einem Thread mit dem Assembler-Fan "Moby" bewiesen 
hat, sind solche Aussagen eine Mischung aus dummen Vorurteilen und 
grobem Unfug. Sogar bei trivialen, kleinen Programmen optimiert der 
AVR-GCC in der Regel besser als ein erfahrener Assembler-Programmierer.

von Thomas E. (picalic)


Lesenswert?

Sheeva P. schrieb:
> Sogar bei trivialen, kleinen Programmen optimiert der
> AVR-GCC in der Regel besser als ein erfahrener Assembler-Programmierer.

Das ist ein genauso dummes Vorurteil, nur in die andere Richtung!
Wie ich weiter oben schon schrieb, bin ich kein erfahrener 
AVR-Assembler-Programmierer und habe trotzdem ein gutes Stück 
Optimierungspotential gefunden.

von Josef G. (bome) Benutzerseite


Lesenswert?

W.S. schrieb:
> for (;;;) blabla...;
> while (1) blabla...;

Zum Thema Endlosschleife mit bedingtem break:
Beitrag "Gibt es eine Programmiersprache mit diesem Schleifentyp?"

von Michael S. (rbs_phoenix)


Lesenswert?

Ich denke, dass es auch viel mit Geschmack zutun hat. Ich persönlich 
nehme i.d.R. nach der Initialisierung vom µC eine while(1)-Schleife. Die 
werden automatisch so eingerückt wie andere Schleifen oder allgemein 
{}Blöcke. Bei einem Goto ist dies nicht der Fall und finde ich 
PERSÖNLICH unübersichtlicher.


Der unterschied besteht eigentlich nur darin, dass man statt
1
while(1){
2
// Argument für Goto
3
// Argument gegen Goto
4
// Beleidigungen austauschen
5
}

auch
1
Anfang:
2
// Argument für Goto
3
// Argument gegen Goto
4
// Beleidigungen austauschen
5
goto Anfang;

schreiben kann. Letztendlich macht der Compiler auch nur ein Goto 
daraus, ob Schleife oder Sprung. Der resultierende Code sollte also der 
gleiche sein.

Bei manchen Dingen bringt es einfach nichts zu diskutieren, weil niemand 
wirklich Recht haben kann.

Meine Meinung

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Thomas E. schrieb:
> Sheeva P. schrieb:
>> Sogar bei trivialen, kleinen Programmen optimiert der
>> AVR-GCC in der Regel besser als ein erfahrener Assembler-Programmierer.
>
> Das ist ein genauso dummes Vorurteil, nur in die andere Richtung!

Nein, das ist das, was Yalu damals nachgewiesen hat: der Proband hatte
eine ziemlich ausgeklügelte Assemblervorlage hingelegt, die sehr
intensiv nur auf einen kleinen, sehr überschaubaren Spezialfall
getrimmt war.

Dennoch war es Yalu gelungen, letztlich ein C-Programm zu zimmern,
dass dieses unterbieten konnte.

> Wie ich weiter oben schon schrieb, bin ich kein erfahrener
> AVR-Assembler-Programmierer und habe trotzdem ein gutes Stück
> Optimierungspotential gefunden.

Vor wieviel Jahren war das?  Wenn es drei Jahre oder mehr her ist,
kannst du das mit dem heutigen Compiler bei weitem nicht mehr
vergleichen.  Seit Johann (Georg Lay) da mal Hand angelegt hat, ist
der Compiler deutlich effizienter geworden (sprich, ab ca. GCC 4.7).

: Bearbeitet durch Moderator
von Soul E. (Gast)


Lesenswert?

Der Controller kennt eh nur JMP und JSR.

Die Regeln zum Coding Style sind Qualitätsmaßnahmen. Qualitätsmanagement 
dient dazu, die Arbeit vom Menschen zu entkoppeln. Wenn Du tot umfällst, 
kann ein anderer Deinen Code weiterpflegen. Der kann dann auch in 
Indien, China oder auf dem Mars sitzen. Das geht nicht, wenn jeder nach 
seinen eigenen Regeln spielt.

von Bitwurschtler (Gast)


Lesenswert?

?Sprungtabelle?
https://de.wikipedia.org/wiki/Sprungtabelle

Wer versteht diesen C-Code ohne gotos besser als einen mit?
1
typedef void (*Handler)(void);    /* A pointer to a handler function */
2
3
/* The functions */
4
void func3 (void) { printf( "3\n" ); }
5
void func2 (void) { printf( "2\n" ); }
6
void func1 (void) { printf( "1\n" ); }
7
void func0 (void) { printf( "0\n" ); }
8
9
Handler jump_table[4] = {func0, func1, func2, func3};
10
11
int main (int argc, char **argv) {
12
    int value;
13
14
    /* Convert first argument to 0-3 integer (modulus) */
15
    value = ((atoi(argv[1]) % 4) + 4) % 4;
16
17
    /* Call appropriate function (func0 thru func3) */
18
    jump_table[value]();
19
20
    return 0;
21
}

von Dussel (Gast)


Lesenswert?

Michael S. schrieb:
> Die werden automatisch so eingerückt wie andere Schleifen
> oder allgemein {}Blöcke. Bei einem Goto ist dies nicht der
> Fall und finde ich PERSÖNLICH unübersichtlicher.
Nicht nur du. Das ist ja der Grund, warum man Goto nicht verwenden soll. 
Bei einer Schleife kann selbst die dumme IDE erkennen, wo sie anfängt 
und wo sie aufhört, ein Programmierer erst Recht, spätestens mit 
Einrückung.
Bei Goto weiß man dagegen nicht, wo es hinspringt. Das heißt, man weiß 
noch nichtmal, in welcher Richtung man suchen soll, und deshalb ist es 
zu vermeiden.

Michael S. schrieb:
> Letztendlich macht der Compiler auch nur ein Goto daraus,
> ob Schleife oder Sprung.
Letztendlich macht der Compiler aus dem Programm Maschinencode. Das ist 
aber kein Argument dafür, in Maschinencode zu programmieren. (Das habe 
ich aus Interesse mal gemacht, und es ist umständlich.) Hochsprachen 
wurden dafür entwickelt, einfacher (verständlich) zu sein und 
Konstrukte, wie Jump, durch übersichtliche Strukturen zu verdecken. Das 
zu umgehen, indem man in Hochsprachen einen Sprungbefehl benutzt, ist in 
nahezu 100% der Fälle sinnlos.

von Clemens L. (c_l)


Lesenswert?

Bitwurschtler schrieb:
> jump_table[value]();

Bei der Frage, ob man goto verwenden sollte, geht es aber um Code 
innerhalb einer Funktion. Mit gcc sähe das dann so aus:
1
int main (int argc, char *argv[])
2
{
3
    static const void *jump_table[4] = {&&func0, &&func1, &&func2, &&func3};
4
5
    int value = ((atoi(argv[1]) % 4) + 4) % 4;
6
7
    goto jump_table[value];
8
9
func0:
10
    printf( "0\n" );
11
    return 0;
12
13
func1:
14
    printf( "1\n" );
15
    return 0;
16
17
func2:
18
    printf( "2\n" );
19
    return 0;
20
21
func3:
22
    printf( "3\n" );
23
    return 0;
24
}

Oder vielleicht doch besser switch() ...

von M. K. (sylaina)


Lesenswert?

Dussel schrieb:
> Bei Goto weiß man dagegen nicht, wo es hinspringt. Das heißt, man weiß
> noch nichtmal, in welcher Richtung man suchen soll, und deshalb ist es
> zu vermeiden.

Ich weiß ja nicht mit welchen IDEs ihr hier alle arbeitet aber meine IDE 
ist in der Lage den Quellcode nach beliebigen Strings zu durchsuchen. 
Auch über mehrere Quellcodedateien hinweg. Da herauszufinden wohin ein 
goto führt ist also heute wirklich kein Kunstwerk mehr...

von MCUA (Gast)


Lesenswert?

Der Controller kennt eh nur JMP und JSR.
aber MCP (wohl als einzigste) nennen das GOTO

von Bitwurschtler (Gast)


Lesenswert?

Clemens L. schrieb:
> Bitwurschtler schrieb:
>> jump_table[value]();

> Oder vielleicht doch besser switch() ...

switch iss aber keine Sprungtabelle da letztere ohne Bedingungsprüfung 
auskommt, aber einen Befehlssatz mit relativen Sprung vorraussetzt.

von kast (Gast)


Lesenswert?

In einem meiner ersten Programme, das ich damals(TM) unter Pascal 
gefrickelt habe, war ich so begeistert von der Macht der Sprünge.
Ich habe GOTOs derart exzessiv/kreuzweise/vor-/rückwärts verwendet,
sodass ich am Ende nicht mehr den Überblick hatte.

GOTO = Teufelszeug

von Bitwurschtler (Gast)


Lesenswert?

kast schrieb:
> In einem meiner ersten Programme, das ich damals(TM) unter Pascal
....
> sodass ich am Ende nicht mehr den Überblick hatte.

Der Überblicksverlust ist bei "erste Programme" völlig normal und nicht 
einzig dem GOTO geschuldet.

Schau dir mal die Pointer-Orgien eines C-Rookies an der cool wirken 
will. Oder das ekstatische Überladen im Code eines OOP-Novizen.

Genies erklären einfach das Chaos zur Ordnung:

https://en.wikipedia.org/wiki/International_Obfuscated_C_Code_Contest#Examples

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Bitwurschtler schrieb:
> Genies erklären einfach das Chaos zur Ordnung:

Du solltest da schon einen Smiley setzen.

Der IOCCC ist bestimmt für irgendwas gut, aber jedenfalls nicht dafür,
dass jemand jemals behauptet hätte, sowas wäre der zu bevorzugende
Programmierstil eines C-Programmierers. ;-)

Aber ja, eine gewisse Genialität benötigt man, um dort erfolgreich zu
sein.  Mit reinem „Anfänger-Chaos“ wird man da eher kein Glück bei der
Jury haben …

von Bitwurschtler (Gast)


Lesenswert?

Jörg W. schrieb:
> Bitwurschtler schrieb:
>> Genies erklären einfach das Chaos zur Ordnung:
>
> Du solltest da schon einen Smiley setzen.

Ja, so war das auch gedacht, als schelmische Bemerkung mit einem Schuß 
Chuzpe - nicht völlig ernst aber auch nicht völlig Banane. Man könnte es 
auch so formulieren:

"Only fools and geniuses uses "Goto" "  };-)

von Hugo (Gast)


Lesenswert?

M. K. schrieb:
> Ich weiß ja nicht mit welchen IDEs ihr hier alle arbeitet aber meine IDE
> ist in der Lage den Quellcode nach beliebigen Strings zu durchsuchen.
> Auch über mehrere Quellcodedateien hinweg. Da herauszufinden wohin ein
> goto führt ist also heute wirklich kein Kunstwerk mehr...

Und bei einem richtig tollen Spaghetticode behältst du mit der 
Suchfunktion den Überblick? ;-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hugo schrieb:
> Und bei einem richtig tollen Spaghetticode behältst du mit der
> Suchfunktion den Überblick? ;-)

Dass man keinen Spaghetticode fabrizieren soll, ist doch nun wirklich
jedem klar.

Aber man muss nun auch nicht so tun, als ob jede Verwendung des
Wortes “goto” automatisch diesen verursachen würde.

Wenn jemand unbedingt nach „reiner Lehre“ arbeiten möchte, dann möge
er bitte auch noch „break“ (aus einer Schleife), „continue“ und
„return“ (ausgenommen exakt am Ende der Funktion, um einen Wert
zurückzugeben) aus seinem Wortschatz verbannen.  Das sind alles nur
„verkappte goto“s.  Ob der Code von solcherart Dogmen wirklich besser
lesbar wird, wage ich zu bezweifeln.

Ansonsten: Donald Knuth wurde ja oben schon genannt, mit seinem
“Structured Programming with Go To”, als Replik auf Dijkstras (aus
Knuth's Sicht) Dogmen.

von Hugo (Gast)


Lesenswert?

Jörg W. schrieb:
> Dass man keinen Spaghetticode fabrizieren soll, ist doch nun wirklich
> jedem klar.
>
> Aber man muss nun auch nicht so tun, als ob jede Verwendung des
> Wortes “goto” automatisch diesen verursachen würde.

Das ist mir schon klar. Ich verteufele das GOTO ja auch nicht generell. 
In manchen Fällen ist es schon angebracht. Ich glaube, da sind wir uns 
einig, daß es durchaus solche Situationen gibt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Hugo schrieb:
> Ich glaube, da sind wir uns einig, daß es durchaus solche Situationen
> gibt.

Ist eigentlich ein schönes Schlusswort für den Thread. ;-)

von Dussel (Gast)


Lesenswert?

Jörg W. schrieb:
> Wenn jemand unbedingt nach „reiner Lehre“ arbeiten möchte, dann möge
> er bitte auch noch „break“ (aus einer Schleife), „continue“ und
> „return“ (ausgenommen exakt am Ende der Funktion, um einen Wert
> zurückzugeben) aus seinem Wortschatz verbannen.  Das sind alles nur
> „verkappte goto“s.
Mit dem Unterschied, dass klar ist, wo die hinspringen. Den Überblick, 
in welcher Schleife oder Funktion man sich befindet, sollte man im 
Allgemeinen schon haben.

Jörg W. schrieb:
> Hugo schrieb:
>> Ich glaube, da sind wir uns einig, daß es durchaus solche Situationen
>> gibt.
>
> Ist eigentlich ein schönes Schlusswort für den Thread. ;-)
So weit waren wir vor einem Monat schon. :-)

von M. K. (sylaina)


Lesenswert?

Dussel schrieb:
> Mit dem Unterschied, dass klar ist, wo die hinspringen. Den Überblick,
> in welcher Schleife oder Funktion man sich befindet, sollte man im
> Allgemeinen schon haben.

Den Überblick sollte man auch bei Verwendung von goto haben und wenn man 
kein Spagetticode damit fabriziert ist der Überblick auch recht gut zu 
halten.

von Thomas E. (picalic)


Lesenswert?

Jörg W. schrieb:
> Vor wieviel Jahren war das?  Wenn es drei Jahre oder mehr her ist,
> kannst du das mit dem heutigen Compiler bei weitem nicht mehr
> vergleichen.  Seit Johann (Georg Lay) da mal Hand angelegt hat, ist
> der Compiler deutlich effizienter geworden (sprich, ab ca. GCC 4.7).

Ist noch nicht so lange her - gegen Ende des letzten Jahres, unter Atmel 
Studio 7.
Welche Version des Compilers genau kann ich grad nicht sagen, bin nicht 
im Büro.

von Oliver S. (oliverso)


Lesenswert?

Dussel schrieb:
> Jörg W. schrieb:
>> Hugo schrieb:
>>> Ich glaube, da sind wir uns einig, daß es durchaus solche Situationen
>>> gibt.
>>
>> Ist eigentlich ein schönes Schlusswort für den Thread. ;-)
> So weit waren wir vor einem Monat schon. :-)

Und immer noch gibts kein Beispiel für solch eine Situation...

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Und immer noch gibts kein Beispiel für solch eine Situation...

Die gibt es massig.  Schau dir einfach die Kernels von *BSD oder
Linux an.
1
% find /sys/ -name \*.c | xargs grep -w goto | wc -l
2
   23976

Selbst, wenn davon 10000 gotos überflüssig wären, blieben immer noch
14000, die es nicht sind.

von W.S. (Gast)


Lesenswert?

Oliver S. schrieb:
> Und immer noch gibts kein Beispiel für solch eine Situation...

Ach?

Wir sind hier im µC-Forum, ja?
Bei unseren Programmen (sprich Firmware) passiert es eigentlich nie, daß 
main mal zurückkehrt. Blöderweise bestehen einige Toolchains darauf, daß 
main vom Typ int sein soll und nicht void sein darf. Und ne int function 
hat gefälligst auch nen Integer zu hinterlassen - auch wenn das vom 
Programmierer garnicht beabsichtigt ist.

Was also schjreibt der geneigte Programmierer?
1
int main (void)
2
{ // initialisierungen
3
  ....
4
5
  while (1)
6
  { // irgendwelcher Inhalt
7
    ...
8
  }
9
  return 0;
10
}

weil er sonst vom Compiler angepfiffen wird. Selber schon unzählige Male 
erlebt.

Wie also geht's besser? So:
1
int main (void)
2
{ // initialisierungen
3
  ....
4
5
  elleweil:
6
   // irgendwelcher Inhalt
7
    ...
8
  goto elleweil;
9
}

Bei diesem Konstrukt merkt der Compiler endlich (!), daß es nie und 
nimmer zurückgeht und hält die Fresse.

Eine andere Baustelle sind Funktionen, wo im Fehlerfalle nicht einfach 
abgebrochen, sondern auch noch aufgeräumt werden muß. Etwa so:
1
int blabla (.....)
2
{ int retcode;
3
4
  Aktion1...  // z.B. File öffnen
5
  retcode=1;
6
  if (!Kondition1()) goto raus_hier;
7
 
8
  Aktion2...  // z.B. parsen
9
  retcode=2;
10
  if (!Kondition2()) goto raus_hier;
11
12
  Aktion2...  // z.B. noch ne Datei öffnen
13
  nochmal sowas wie oben
14
15
  retcode=Is_OK;
16
  MachSonstwas...
17
18
raus_hier:
19
  RäumeAuf, SchließeAb...
20
  return RetCode;
21
}

Natürlich könnte man das alles ohne goto's nur mit if's schachteln oder 
das Aufräumen und Abschließen bei jeder fehlgeschlagenen Kondition 
separat hinschreiben, aber das ist erstens aufwendiger, zweitens 
schlechter lesbar und drittens müßte man bei jeder Änderung am 
Aufräumcode selbigen n-mal ändern.

Es ist ja nicht so, daß man goto an jeder Ecke dreimal braucht, aber es 
generell zu verteufeln ist schlichtweg engstirnig.

W.S.

von Falk B. (falk)


Lesenswert?

@ W.S. (Gast)

>main mal zurückkehrt. Blöderweise bestehen einige Toolchains darauf, daß
>main vom Typ int sein soll und nicht void sein darf.

Ist halt so.

>Was also schjreibt der geneigte Programmierer?

>int main (void)
>{ // initialisierungen
>  ....

>  while (1)
>  { // irgendwelcher Inhalt
>    ...
>  }
>  return 0;
>}

>weil er sonst vom Compiler angepfiffen wird. Selber schon unzählige Male
>erlebt.

Na dann schreib es doch einfach und vergiss die Sache! Mein Gott, das 
sind Luxusprobleme!

>Wie also geht's besser? So:

Besser? Murks^3!

>Eine andere Baustelle sind Funktionen, wo im Fehlerfalle nicht einfach
>abgebrochen, sondern auch noch aufgeräumt werden muß. Etwa so:

Dies allgemeine Aussage hatten wir schon dutzendfach. Ein WIRKLICH 
überzeugendes Beispiel aus der PRAXIS fehlt immer noch. Die Skizze 
reicht nicht.

>Es ist ja nicht so, daß man goto an jeder Ecke dreimal braucht, aber es
>generell zu verteufeln ist schlichtweg engstirnig.

Das hatten wir schon x-fach.

von W.S. (Gast)


Lesenswert?

Du klingst recht fanatisch - und Fanatiker kann man mit keiner Wahrheit 
überzeugen.

Also wenn du dir Augen und Ohren zuhältst und dann rufst "ich kann keine 
Argumente sehen noch hören", dann bleib einfach dabei.

W.S.

von Dussel (Gast)


Lesenswert?

W.S. schrieb:
> Was also schjreibt der geneigte Programmierer?
> [Zu viele Zitatzeilen]
> weil er sonst vom Compiler angepfiffen wird. Selber schon unzählige Male
> erlebt.
Das habe ich gerade mit XCode ausprobiert und der Compiler sagt gar 
nichts. Das 'Schlimmste', das ich in dem Fall erlebt habe, war eine 
Warnung 'Unreachable Statement'. Wenn du so dünnhäutig bist, dass dich 
eine Warnung so fertig macht, kannst du auch Goto verwenden, aber das 
ist absolut nicht die Regel.

von Bernd K. (prof7bit)


Lesenswert?

W.S. schrieb:
> Was also schjreibt der geneigte Programmierer?
> int main (void)
> { // initialisierungen
>   ....
>
>   while (1)
>   { // irgendwelcher Inhalt
>     ...
>   }
>   return 0;
> }
>
> weil er sonst vom Compiler angepfiffen wird. Selber schon unzählige Male
> erlebt.
>
> Wie also geht's besser? So:
> int main (void)
> { // initialisierungen
>   ....
>
>   elleweil:
>    // irgendwelcher Inhalt
>     ...
>   goto elleweil;
> }
>
> Bei diesem Konstrukt merkt der Compiler endlich (!),

Ist schon wieder Märchenstunde mit W.S?

Erstens ist mir noch kein Compiler begegnet der mich wegen meiner int 
main(void) angepfiffen hat, selbst auf der schärfsten Warnstufe nicht 
und zweitens merkt er bei while(1) sehr wohl daß die Schleife unendlich 
ist, die beiden Beispiele oben sind diesbezüglich vollkommen äquivalent, 
das goto ist überflüssig, mit while(1) gehts genauso und sieht schöner 
aus.

begin dummy text
Bitte reduzieren Sie die Anzahl der Zitatzeilen. Bitte reduzieren Sie 
die Anzahl der Zitatzeilen. Bitte reduzieren Sie die Anzahl der 
Zitatzeilen. Bitte reduzieren Sie die Anzahl der Zitatzeilen. Bitte 
reduzieren Sie die Anzahl der Zitatzeilen. Bitte reduzieren Sie die 
Anzahl der Zitatzeilen. Bitte reduzieren Sie die Anzahl der Zitatzeilen. 
Bitte reduzieren Sie die Anzahl der Zitatzeilen. Bitte reduzieren Sie 
die Anzahl der Zitatzeilen. Bitte reduzieren Sie die Anzahl der 
Zitatzeilen. Bitte reduzieren Sie die Anzahl der Zitatzeilen. Bitte 
reduzieren Sie die Anzahl der Zitatzeilen. Bitte reduzieren Sie die 
Anzahl der Zitatzeilen. Bitte reduzieren Sie die Anzahl der Zitatzeilen. 
Bitte reduzieren Sie die Anzahl der Zitatzeilen. Bitte reduzieren Sie 
die Anzahl der Zitatzeilen. Bitte reduzieren Sie die Anzahl der 
Zitatzeilen.
end dummy text

: Bearbeitet durch Moderator
von Rolf M. (rmagnus)


Lesenswert?

Jörg W. schrieb:
> Nein, das ist das, was Yalu damals nachgewiesen hat: der Proband hatte
> eine ziemlich ausgeklügelte Assemblervorlage hingelegt, die sehr
> intensiv nur auf einen kleinen, sehr überschaubaren Spezialfall
> getrimmt war.
>
> Dennoch war es Yalu gelungen, letztlich ein C-Programm zu zimmern,
> dass dieses unterbieten konnte.

Und mit diesem einen Beispiel hat er nachgewiesen, dass das "in der 
Regel" so ist?

soul e. schrieb:
> Der Controller kennt eh nur JMP und JSR.
>
> Die Regeln zum Coding Style sind Qualitätsmaßnahmen. Qualitätsmanagement
> dient dazu, die Arbeit vom Menschen zu entkoppeln. Wenn Du tot umfällst,
> kann ein anderer Deinen Code weiterpflegen.

Oder wenn du in Urlaub gehst und nach der Rückkehr immer noch an dem 
Code arbeiten musst.

W.S. schrieb:
> Bei unseren Programmen (sprich Firmware) passiert es eigentlich nie, daß
> main mal zurückkehrt. Blöderweise bestehen einige Toolchains darauf, daß
> main vom Typ int sein soll und nicht void sein darf.

Das ist in ISO C ja auch so vorgeschrieben.

> Bei diesem Konstrukt merkt der Compiler endlich (!), daß es nie und
> nimmer zurückgeht und hält die Fresse.

Aha, du nutzt also goto in diesem Fall nur, um auf "geschickte" Weise 
die Regeln zu umgehen, damit du es dir sparen kannst, ein extra "return 
0;" in die Tasten zu hämmern...

> Eine andere Baustelle sind Funktionen, wo im Fehlerfalle nicht einfach
> abgebrochen, sondern auch noch aufgeräumt werden muß. Etwa so:
> int blabla (.....)
> { int retcode;
>
>   Aktion1...  // z.B. File öffnen
>   retcode=1;
>   if (!Kondition1()) goto raus_hier;
>
>   Aktion2...  // z.B. parsen
>   retcode=2;
>   if (!Kondition2()) goto raus_hier;
>
>   Aktion2...  // z.B. noch ne Datei öffnen
>   nochmal sowas wie oben
>
>   retcode=Is_OK;
>   MachSonstwas...
>
> raus_hier:
>   RäumeAuf, SchließeAb...
>   return RetCode;
> }

Für mich ist eine Erweiterung dieses Falles erst so richtig ein Grund, 
goto zu nutzen. Meist muss man schließlich nicht in jedem Fehlerfall das 
selbe Cleanup machen. Wenn z.B. das File nicht geöffnet werden konnte, 
darf ich auch nicht versuchen, es zu schießen. Ich muss also quasi in 
umgekehrter Reihenfolge der Aktionen mehrere Cleanup-Aktionen 
durchführen, aber nur den Teil davon, zu dem auch die Aktionen 
erfolgreich waren.

> Es ist ja nicht so, daß man goto an jeder Ecke dreimal braucht, aber es
> generell zu verteufeln ist schlichtweg engstirnig.

Das sehe ich ganz genauso.

Bernd K. schrieb:
> begin dummy text
> Bitte reduzieren Sie die Anzahl der Zitatzeilen.
> [...]

Gibt es einen speziellen Grund, warum du das X mal postest, statt es 
einfach zu tun?

von nichtCler (Gast)


Lesenswert?

In C gibt es goto weil das C-nahe Assembler auch nicht ohne equivalentes 
auskommt :)

von M. K. (sylaina)


Lesenswert?

Dussel schrieb:
> Das 'Schlimmste', das ich in dem Fall erlebt habe, war eine
> Warnung 'Unreachable Statement'. Wenn du so dünnhäutig bist, dass dich
> eine Warnung so fertig macht, kannst du auch Goto verwenden, aber das
> ist absolut nicht die Regel.

Das erste was uns eingeprügelt wurde von unserem Info-Prof:

There is no reason to ignore warnings.

Und IMO hat er Recht, daher kommt beim Compiler auch immer die -Wall und 
das liebe -Werror zum Einsatz

von W.S. (Gast)


Lesenswert?

Dussel schrieb:
> Das 'Schlimmste', das ich in dem Fall erlebt habe, war eine
> Warnung 'Unreachable Statement'.

Reicht das nicht?

Entweder gibt es vom Compiler keine Fehler und Warnungen oder es liegt 
eben was im Argen - was auch immer. Willst du bei jedem Compilerlauf 
überprüfen, ob genau diese Warnung nun tatsächlich ignorabel ist oder 
ist dir das schnurz?

Hier hab ich es also offensichtlich mit Leuten zu tun, die aus schierer 
Abneigung gegen ein simples goto selbst Compilerwarnungen in Kauf 
nehmen.

Ist mir völlig unverständlich. Ich pack das in die Schublade 
"Fanatismus".

W.S.

von Dussel (Gast)


Lesenswert?

M. K. schrieb:
> Das erste was uns eingeprügelt wurde von unserem Info-Prof:
>
> There is no reason to ignore warnings.
Das hätte ich eher von einem Deutschen erwartet. Wir gelten doch als 
regelhörig. :-)

M. K. schrieb:
> Und IMO hat er Recht, daher kommt beim Compiler auch immer die -Wall und
> das liebe -Werror zum Einsatz
Man soll sie ja auch nicht ignorieren - 'wird schon passen' - sondern 
sie sich anschauen und überlegen, ob man 'Gegenmaßnahmen' treffen muss. 
Wenn ich aber eine Endlosschleife schreibe, die auch eine Endlosschleife 
sein soll, ist mir klar, dass Befehle dahinter nicht erreicht werden.
Was ist denn dann der Unterschied zwischen einem Fehler und einer 
Warnung, wenn man eine Warnung wie einen Fehler behandeln soll?

W.S. schrieb:
> Hier hab ich es also offensichtlich mit Leuten zu tun, die aus schierer
> Abneigung gegen ein simples goto selbst Compilerwarnungen in Kauf
> nehmen.
Wie ich gerade schon schrieb, habe ich keine Warnung bekommen und kann 
mich auch im AVR Studio nicht daran erinnern.

W.S. schrieb:
> Ist mir völlig unverständlich. Ich pack das in die Schublade
> "Fanatismus".
Dahin packe ich dich. Dann sind wir jetzt beide mehr oder weniger 
glücklich.

von Fpgakuechle K. (Gast)


Lesenswert?

M. K. schrieb:

> There is no reason to ignore warnings.
>
> Und IMO hat er Recht, daher kommt beim Compiler auch immer die -Wall und
> das liebe -Werror zum Einsatz

Klar ganz besonder bei
-Wunused-label

weil das auf vergessenes goto hinweist ;-)


-Wno-unused-result
Grad im embedded bereich gibt es Fälle wo das Ergebnis eben nicht 
interessiert sondern allein die Bitschubserei mittendrin

Auch bei generierten Code wird man um schmerzfreie warnings nicht 
drumherum kommen.

von M. K. (sylaina)


Lesenswert?

Dussel schrieb:
> Was ist denn dann der Unterschied zwischen einem Fehler und einer
> Warnung, wenn man eine Warnung wie einen Fehler behandeln soll?

Dass man sich darum kümmert die Warnung zu beseitigen.
In meiner jetzt fast 20-jährigen Berufserfahrung kann ich sagen: Es gibt 
immer einen Weg einen Code so zu schreiben, dass der Compiler keine 
Warnung wirft und das Programm dennoch so funktioniert wie man es sich 
wünscht/vorstellt. ;)
Warnungen "ignoriere" ich bestenfalls für einen Testlauf, mehr aber auch 
nicht. (z.B. wenn mich der Compiler informiert dass er bei der 
LCD-Routine den "qualifier" "volatile" der globalen Variablen xyz 
"entfernt" hat.)

von Dussel (Gast)


Lesenswert?

M. K. schrieb:
> Dass man sich darum kümmert die Warnung zu beseitigen.
Und den Fehler beseitigt man nicht? :D

von M. K. (sylaina)


Lesenswert?

Bei dir laufen Programme obwohl der Compiler Fehler geworfen hat? 
Beeindruckend, meiner macht da erst gar kein Hexfile draus. ;)

von Dussel (Gast)


Lesenswert?

M. K. schrieb:
> Bei dir laufen Programme obwohl der Compiler Fehler geworfen hat?
> Beeindruckend, meiner macht da erst gar kein Hexfile draus. ;)
Meinst du mich?
Du hast ausgedrückt, dass man Fehler nicht beseitigt, denn das sei der 
Unterschied zu Warnungen, die man beseitigen soll.
Anscheinend sind manche hier schon betrunken. Ich noch nicht, ich mache 
mich jetzt erst fertig. Bis morgen (Mittag) ;-)

(Das ist nicht ganz ernst gemeint, trotzdem verstehe ich nicht, was du 
meinst. Weg bin ich aber wirklich.)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
>> Dennoch war es Yalu gelungen, letztlich ein C-Programm zu zimmern,
>> dass dieses unterbieten konnte.
>
> Und mit diesem einen Beispiel hat er nachgewiesen, dass das "in der
> Regel" so ist?

Nun, er hat es für den Fall nachgewiesen, für den es wirklich
niemand erwartet hätte, dass da noch was rauszuholen ist: für ein
extrem minimalistisches, in seiner Funktion recht überschaubares
(und dadurch auf Assemblerniveau gut zusammenzustauchendes) Stück
Code.

Für jeglichen Code von einigen Kilobyte Größe hätte (außer Moby)
ohnehin niemand gezweifelt, dass der Compiler das schafft, weil man
das auf Assemblerebene als Programmierer nicht mehr hinreiched gut
überblicken kann.

von M. K. (sylaina)


Lesenswert?

Dussel schrieb:
> Du hast ausgedrückt, dass man Fehler nicht beseitigt, denn das sei der
> Unterschied zu Warnungen, die man beseitigen soll.

Was? Wo hab ich denn das ausgedrückt?

Dussel schrieb:
> Anscheinend sind manche hier schon betrunken. Ich noch nicht

Ich glaube du irrst dich hierbei...

Dussel schrieb:
> (Das ist nicht ganz ernst gemeint, trotzdem verstehe ich nicht, was du
> meinst. Weg bin ich aber wirklich.)

Ich meinte damit, dass man, neben den Fehlern zu beseitigen, auch die 
Warnungen beseitigen sollte. Das war aber jetzt aus dem Kontext nicht 
wirklich schwer zu verstehen. Hoffe du hast noch eine/n schöne/n 
Abend/Nacht

von Bernd K. (prof7bit)


Lesenswert?

Rolf M. schrieb:
> Gibt es einen speziellen Grund, warum du das X mal postest, statt es
> einfach zu tun?

Das Zitat war notwendig für den Kontext meiner Antwort. Es war nicht 
weiter kürzbar. Wenn die Forensoftware dann sinnloserweise mehr Text 
sehen will soll sie ihn meinetwegen bekommen, ist nicht mein Storage und 
auch nicht meine Bandbreite, das hat der bestellt der sich diesen Unsinn 
ausgedacht hat.

von Zeno (Gast)


Lesenswert?

Bernd K. schrieb:
> Erstens ist mir noch kein Compiler begegnet der mich wegen meiner int
> main(void) angepfiffen hat

Du hast den Post von W.S. nicht richtig gelesen. W.S. hatte davon 
gesprochen die main-Funktion als void zu deklarieren, was bei einigen 
Compilern eben nicht funktioniert. Bei µC brauche ich für die 
main-Funktion keinen Rückgabewert, da dieser niemals ausgewertet wird.
Das Dein
1
int main(void)
 läuft hat er ja gar nicht bestritten.

Seine Goto - Lösung finde ich an dieser Stelle gar nicht so schlecht. 
Das bei C an dieser Stelle benutzte
1
while(1)
 bringt an dieser Stelle auch nicht mehr Vorteile oder Übersicht.
Gerade als Anfänger muß man erst mal darauf kommen, daß man while so 
aufrufen kann. Goto entspricht da eher der menschlichen Logik.

Das while(1) ist nach meinem Verständis ein genauso unsägliches 
Konstrukt wie for(;;;). Es gibt gute Gründe warum andere 
Programmiersprachen so was verbieten.

Es ist schon erstaunlich wie man sich an einem simplen goto aufgeilen 
kann.
Ich bin der Meinung das man den Sprachumfang einer Programmiersprache 
auch vollumfänglich benutzen kann, auch wenn es sich dabei um das 
umstrittene goto oder bei C um while(1) bzw. for(;;;) handelt. Es gibt 
immer Fälle wo solche Konstrukte durchaus Sinn machen und 
übersichtlichen Code produzieren.
Sicherlich lassen sich auch immer andere Lösungen finden, aber ob die 
nun wirklich besser sind steht auf einem anderen Blatt.

Zeno

von Oliver S. (oliverso)


Lesenswert?

Zeno schrieb:
> Goto entspricht da eher der menschlichen Logik.

Genau. Das sieht man immer wieder an den Erstlingsprogrammmen von 
Programmieranfängern. Menschliche Logik ist dafür der falsche Ansatz.

Wer sich an einem while(1) stört, hat noch nicht mal die Grundlagen der 
Programmiersprache verinnerlicht. An der Stelle ist ein goto zwar 
möglich, aber genauso wenig hilfreich, wie in all den anderen Beispielen 
hier.

Sinnvoll ist es in sehr speziellen Fällen zur Fehlerbehandlung, aber 
selbst da bietet C verkappte gotos in Form von setjmp/longjmp, und in 
C++ wirft man dann Exceptions. Auf ganz kleinen Mikros wird's damit 
allerdings eng. Da hilft dann goto.

Oliver

von asdf (Gast)


Lesenswert?

Zeno schrieb:
> ein genauso unsägliches
> Konstrukt wie for(;;;)

Vor allem deshalb, weil es das gar nicht gibt :-)

Lies mal nach und vergleiche:
http://www.c-howto.de/tutorial-schleifen-for.html

von Oliver S. (oliverso)


Lesenswert?

Versuch macht kluch...

Und dann mal K&R lesen.

Oliver

von asdf (Gast)


Lesenswert?

Oliver S. schrieb:
> Und dann mal K&R lesen.

Okay:
The syntax of a for loop in C programming language is −

for ( init; condition; increment )

Und du schreibst:
for ( init; condition; increment; _???_ )

Fällt dir vielleicht jetzt was auf?

von Bernd K. (prof7bit)


Lesenswert?

Zeno schrieb:
> Das Deinint main(void) läuft hat er ja gar nicht bestritten.

Doch, er hat behauptet es gäbe irgendwelche Warnungen und mit goto könne 
er sie abstellen. Das entspricht aber nicht der Wahrheit.

> Seine Goto - Lösung finde ich an dieser Stelle gar nicht so schlecht.

Wozu? Jeder Mensch benutzt an dieser Stelle ein while(1) Konstrukt. 
Sollte ich jemals Software vererbt bekommen die an der Stelle ein goto 
verwendet würde ich wahrscheinlich erstmal 26 Sekunden lang WTF??? 
WTF??? fragen und irgendeinen hinterhältigen versteckten schmutzigen 
Trick vermuten den ich übersehen habe und nach weiteren 18 Sekunden in 
denen ich so einen Trick nicht finden kann den ganzen Schwachsinn gegen 
ein ganz normales while(1) austauschen.

An irgendwelchen von W.S. herbeiphantasierten (aber nicht existierenden) 
Warnungen ändert das nicht das geringste. Und mit dem Rückgabewert hat 
das auch nichts zu tun.

von Helmut L. (helmi1)


Lesenswert?

Dann schreibt doch einfach:

#define forever  for(;;)



und dann im Programm einfach:

    forever
    {
    }

so sollte auch der letzte DAP  das lesen koennen.

DAP = duemmster anzunehmender Programmierer

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Dussel schrieb:
>> Das 'Schlimmste', das ich in dem Fall erlebt habe, war eine
>> Warnung 'Unreachable Statement'.
>
> Reicht das nicht?
>
> Entweder gibt es vom Compiler keine Fehler und Warnungen oder es liegt
> eben was im Argen - was auch immer.

Nein. Eine Warnung heißt nicht automatisch, dass der Code falsch ist, 
und die Abwesenheit einer Warnung heißt genausowenig, dass der Code 
perfekt ist. Das erkennt man schon alleine daran, dass unterschiedliche 
Compiler auch in unterschiedlichen Situationen warnen.

> Hier hab ich es also offensichtlich mit Leuten zu tun, die aus schierer
> Abneigung gegen ein simples goto selbst Compilerwarnungen in Kauf
> nehmen.

Was für ein Unsinn. Wenn ich bei deinem Beispiel das "return 0;" 
hinschreibe, kommt bei mir irgendwie keine Warnung, trotz Nichtbenutzung 
von goto. Die Warnung kommt doch auch gar nicht, weil du kein goto 
benutzt hast, sondern weil du das return unterschlagen hast. Also ist 
deren Vermeidung auch überhaupt kein Argument für goto.

> Ist mir völlig unverständlich.

Das merkt man...

M. K. schrieb:
> In meiner jetzt fast 20-jährigen Berufserfahrung kann ich sagen: Es gibt
> immer einen Weg einen Code so zu schreiben, dass der Compiler keine
> Warnung wirft und das Programm dennoch so funktioniert wie man es sich
> wünscht/vorstellt. ;)

Einen Weg gibt es immer. Die Frage ist nur, ob man es immer hinnimmt, im 
Code Verrenkungen anstellen zu müssen, nur weil der Compiler bei einem 
eigentlich völlig korrekten Code-Konstrukt warnt.

M. K. schrieb:
> Dussel schrieb:
>> Du hast ausgedrückt, dass man Fehler nicht beseitigt, denn das sei der
>> Unterschied zu Warnungen, die man beseitigen soll.
>
> Was? Wo hab ich denn das ausgedrückt?

Hier:

M. K. schrieb:
> Dussel schrieb:
>> Was ist denn dann der Unterschied zwischen einem Fehler und einer
>> Warnung, wenn man eine Warnung wie einen Fehler behandeln soll?
>
> Dass man sich darum kümmert die Warnung zu beseitigen.

Zeno schrieb:
> Du hast den Post von W.S. nicht richtig gelesen. W.S. hatte davon
> gesprochen die main-Funktion als void zu deklarieren, was bei einigen
> Compilern eben nicht funktioniert. Bei µC brauche ich für die
> main-Funktion keinen Rückgabewert, da dieser niemals ausgewertet wird.

Ich verstehe allerdings nicht, wozu das gut sein soll. Ich hatte noch 
nie ein Problem dadurch, dass ich main() einen int zurückliefern hab 
lassen. Im schlimmsten Fall braucht das das eine oder andere zusätzliche 
Byte, aber wenn der Speicher schon so knapp ist, dass das ein Problem 
ist, hab ich eh verloren.

> Seine Goto - Lösung finde ich an dieser Stelle gar nicht so schlecht.

Ich finde es widersinnig. Nur um sich in main() das return zu sparen, 
nutzt er goto, weil sein Compiler in dem Fall nicht warnt - zumindest in 
der Version, die er aktuell nutzt. Das ist dann in seinen Augen das 
Argument dafür, für Endlosschleifen grundsätzlich immer goto zu 
verwenden.

> Das bei C an dieser Stelle benutzte while(1) bringt an dieser Stelle auch
> nicht mehr Vorteile oder Übersicht.

Doch, finde ich schon. Es ist konsistent. Ich habe eine Schleife, also 
schreib ich die auch als eine solche hin, auch dann, wenn sie mal kein 
Abbruchkriterium hat. Wobei ich for (;;) bevorzuge, da ich da die 
Bedinung dann auch wirklich weglassen kann, während ich beim while in 
dem Fall eine Pseudo-Bedingung hinschreiben muss. Man könnte aber 
natürlich schreiben:
1
#define WEIHNACHTEN 1
2
#define OSTERN 2
3
4
while (WEIHNACHTEN != OSTERN)

;-)

> Das while(1) ist nach meinem Verständis ein genauso unsägliches
> Konstrukt wie for(;;;). Es gibt gute Gründe warum andere
> Programmiersprachen so was verbieten.

Mir würde keiner einfallen, und "unsäglich" finde ich den auch nicht, 
sondern im Gegenteil viel eher "natürlich", als für Endlosschleifen auf 
einmal einen ganz anderen Konstrukt zu verwenden, als bei allen anderen 
Schleifen.

> Ich bin der Meinung das man den Sprachumfang einer Programmiersprache
> auch vollumfänglich benutzen kann,

Ja, sehe ich auch so, wobei man aber nicht unbedingt alles benutzen 
muss, nur weil es eben da ist. Man benutzt immer das, was einem an der 
Stelle am sinnvollsten erscheint. Das kann auch dazu führen, dass man 
bestimmte Teile der Sprache nicht nutzt. Es gibt keine Notwendigkeit, 
zwingend jedes Element der Sprache auch nutzen zu müssen.

> Sicherlich lassen sich auch immer andere Lösungen finden, aber ob die
> nun wirklich besser sind steht auf einem anderen Blatt.

Richtig.

von Bernd K. (prof7bit)


Lesenswert?

Rolf M. schrieb:
> Was für ein Unsinn. Wenn ich bei deinem Beispiel das "return 0;"
> hinschreibe, kommt bei mir irgendwie keine Warnung, trotz Nichtbenutzung
> von goto. Die Warnung kommt doch auch gar nicht, weil du kein goto
> benutzt hast, sondern weil du das return unterschlagen hast.

Die Warnung verschwindet auch dann wenn man das return NICHT 
hinschreibt aber ein while(1) hat das niemals verlassen wird.

Es ist diesbezüglich Jacke wie Hose ob man das mit while oder goto 
macht, in beiden Fällen gibts keine Warnung weil in beiden Fällen jeder 
Compiler der sein Geld wert ist erkennt daß die Funktion niemals 
zurückkehrt und die Warnung verschwindet sobald das endlose while dort 
steht.

Probierts doch selber mal aus.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Bernd K. schrieb:
> Probierts doch selber mal aus.

Ok, hab ich mal getan. Bei mir (gcc 5.2.1) kommt weder bei der while-, 
noch bei der goto-Variante eine Warnung, egal ob ich das return 
hinschreibe oder nicht. Getestet mit -pedantic -Wall -Wextra, einmal im 
C89- und einmal im C99-Modus. Mit anderen Worten: Die Rechtfertigung von 
W.S., an dieser Stelle goto zu benutzen, um die Warnung zu vermeiden, 
ist völliger Blödsinn.

Ohne die Endlosschleife kommt übrigens bei fehlendem return nur im 
C89-Modus eine Warnung.

: Bearbeitet durch User
von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Rolf M. schrieb:

> Ohne die Endlosschleife kommt übrigens bei fehlendem return nur im
> C89-Modus eine Warnung.

Zumindest in C++ ist das return statement in der main() Funktion 
optional und da wird auch kein vernünftiger Compiler eine Warnung 
ausgeben. Vielleicht gibt es diese Erweiterung auch in aktuelleren C 
Standards?

von M. K. (sylaina)


Lesenswert?

Rolf M. schrieb:
> Einen Weg gibt es immer. Die Frage ist nur, ob man es immer hinnimmt, im
> Code Verrenkungen anstellen zu müssen, nur weil der Compiler bei einem
> eigentlich völlig korrekten Code-Konstrukt warnt.

Wenn das Konstrukt korrekt wäre würde der Compiler nicht warnen.

Rolf M. schrieb:
> Hier:

Da schrieb ich nur, dass man die Warnungen beseitigen solle, ich schrieb 
da aber nicht, dass man nur die Warnungen beseitigen solle noch dass man 
die Fehler nicht beseitigen solle. Keine Ahnung wie ihr auf sowas 
geschlossen habt.

von Dussel (Gast)


Lesenswert?

M. K. schrieb:
> Wenn das Konstrukt korrekt wäre würde der Compiler nicht warnen.
Umgekehrt. Wenn das Konstrukt nicht korrekt wäre, würde der Compiler 
nicht nur warnen.
Manche Compiler warnen bei unbenutzten Variablen. Trotzdem ist ein 
Programm, das eine nicht benutzte Variable enthält, vollkommen korrekt 
und unterscheidet sich bei heutigen Compilern im Ergebnis nicht von 
einem Programm, das diese Variable nicht enthält.

M. K. schrieb:
> Da schrieb ich nur, dass man die Warnungen beseitigen solle, ich schrieb
> da aber nicht, dass man nur die Warnungen beseitigen solle noch dass man
> die Fehler nicht beseitigen solle. Keine Ahnung wie ihr auf sowas
> geschlossen habt.
Doch, genau das. Deiner Aussage nach ist der Unterschied zwischen 
Fehlern und Warnungen, dass man Warnungen beseitigen soll. Fehler solle 
man in dem Aspekt anders [unterschiedlich zu Warnungen] behandeln, was 
ich so interpretiere, dass man Fehler eben nicht beseitigen soll.

von Dussel (Gast)


Lesenswert?

Genau genommen hätte ich den zweiten Teil nicht schreiben sollen. Die 
Diskussion führt zu nichts.

Worin wir uns wohl alle (zumindest insgeheim) einig sind ist, dass 
Anfänger Goto nicht verwenden sollen.
Wenn man weiß, was man macht, gibt es Anwendungsfälle, in denen Goto 
sinnvoll ist (wie schon seit einem Monat immer wieder gesagt wird). 
Welche Fälle das sind, muss man im Zweifelsfall mit seinen Vorgesetzten 
und Mitarbeitern diskutieren.

von Rolf M. (rmagnus)


Lesenswert?

M. K. schrieb:
> Rolf M. schrieb:
>> Einen Weg gibt es immer. Die Frage ist nur, ob man es immer hinnimmt, im
>> Code Verrenkungen anstellen zu müssen, nur weil der Compiler bei einem
>> eigentlich völlig korrekten Code-Konstrukt warnt.
>
> Wenn das Konstrukt korrekt wäre würde der Compiler nicht warnen.

Wie ich schon schrieb: Eine Warnung heißt nicht zwangsläufig, dass es 
falsch ist. Es heißt nur, dass der Compiler etwas gefunden hat, das 
dessen Hersteller für verdächtig hält.

> Rolf M. schrieb:
>> Hier:
>
> Da schrieb ich nur, dass man die Warnungen beseitigen solle, ich schrieb
> da aber nicht, dass man nur die Warnungen beseitigen solle noch dass man
> die Fehler nicht beseitigen solle. Keine Ahnung wie ihr auf sowas
> geschlossen habt.

Du hast auf die Frage, was der Unterschied zwischen Warnung und Fehler 
ist, geantwortet, dass man Warnungen beseitigen muss. Wenn das der 
Unterschied zu Fehlern ist, heißt das aber, dass man Fehler nicht 
beseitigen muss.

von Zeno (Gast)


Lesenswert?

asdf schrieb:
> Zeno schrieb:
>> ein genauso unsägliches
>> Konstrukt wie for(;;;)
>
> Vor allem deshalb, weil es das gar nicht gibt :-)

Na da ist aber einer froh, daß er was gefunden hat. Ja da ist ein ; zu 
viel. Das ändert aber dennoch nichts daran, das die for-Schleife ohne 
Parameter ein unsägliches Konstrukt ist, was sich einem nicht logisch 
erschließt. Deshalb muß man's halt nachlesen.

Ich komme nicht aus der C-Ecke und benutze derzeit C nur um ab und zu 
einen µC zu programmieren. Bisher bin ich ohne for(;;) ausgekommen. 
Meine Endlosschleife habe ich bisher mit while(1) gemacht und werde dies 
auch weiterhin so tun oder W.S. Ansatz mit dem goto verwenden.

ZEno

von Hugo (Gast)


Lesenswert?

Zeno schrieb:
> Bisher bin ich ohne for(;;) ausgekommen.
> Meine Endlosschleife habe ich bisher mit while(1) gemacht

Eine for-Schleife ohne Parameter findest du also "unsäglich", aber eine 
while-Schleife ohne Parameter ist in Ordnung für dich?

Na gut, jedem Tierchen sein Pläsierchen :-)

von Zeno (Gast)


Lesenswert?

Bernd K. schrieb:
> Zeno schrieb:
>> Das Deinint main(void) läuft hat er ja gar nicht bestritten.
>
> Doch, er hat behauptet es gäbe irgendwelche Warnungen und mit goto könne
> er sie abstellen. Das entspricht aber nicht der Wahrheit.

Nein Du hast den Post von W.S. nicht richtig gelesen. Er hat folgendes 
geschrieben:

W.S. schrieb:
> daß main vom Typ int ....

Die Compilermecker bezieht er auf den (zu definierenden) Rückgabewert 
von main, also auf das int vor main.

CCS von TI meckert bei eingestellten GCC wenn man main so definiert:
1
void main(void)
2
{
3
....
4
}

Dabei ist es egal ob man als Endlosschleife while(1), for(;;) oder 
W.S.'s goto nimmt.

Zeno

von Zeno (Gast)


Lesenswert?

Rolf M. schrieb:
> Es gibt keine Notwendigkeit,
> zwingend jedes Element der Sprache auch nutzen zu müssen

Das habe ich so (Betonung auf zwingend) nicht gesagt. Ich wollte meinen 
Post so verstanden wissen, daß man den kompletten Sprachumfang nutzen 
kann wenn man dies denn in bestimmten Situationen für vorteilhaft 
erachtet.


Zeno

von Zeno (Gast)


Lesenswert?

Hugo schrieb:
> while-Schleife ohne Parameter ist in Ordnung für dich?

1 ist bei while(1) wohl kein Parameter?  Ohne Parameter müßte es ja so 
heißen while().

Ich habe nicht gesagt, das ich das while(1) gut finde, aber wenn man 
zwischen mehreren Seuchen wählen muß, um zum Ziel zu kommen, dann muß 
man sich halt für Eine entscheiden.

Zeno

von Paul B. (paul_baumann)


Lesenswert?

Zeno schrieb:
> Ohne Parameter müßte es ja so
> heißen while().

Warte, warte noch ein While-chen,
dann kommt Goto auch zu Dir!
Mit dem dem kleinen For-Next Schleifchen
steht es dann vor Deiner Tür.

MfG Paul

von Bernd K. (prof7bit)


Lesenswert?

Zeno schrieb:
> W.S. schrieb:
>> daß main vom Typ int ....
>
> Die Compilermecker bezieht er auf den (zu definierenden) Rückgabewert
> von main, also auf das int vor main.

Na und? Er hat aber geschrieben daß er es [wasauchimmer] mit goto 
abstellen kann, mit while(1) aber nicht. Das ist aber Unfug denn auch 
mit while(1) gibt es keine Warnung, mithin also keinen Grund für goto an 
der Stelle.
1
int main (void) {
2
    while (1) {
3
        // tuwas
4
    }
5
}

gibt keine Warnung. Und zwar weil alles korrekt ist. Genauso wie man es 
erwarten würde. Also was soll der ganze Aufriss und welche Rolle soll 
goto hier spielen die das while(1) nicht erfüllen kann?

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Dussel schrieb:
> Doch, genau das. Deiner Aussage nach ist der Unterschied zwischen
> Fehlern und Warnungen, dass man Warnungen beseitigen soll. Fehler solle
> man in dem Aspekt anders [unterschiedlich zu Warnungen] behandeln, was
> ich so interpretiere, dass man Fehler eben nicht beseitigen soll.

Sorry, aber so einen Unsinn hab ich schon lange nicht mehr gelesen. Nur 
weil ich nicht schrieb, dass man auch Fehler beseitigen soll (genauer: 
ich hab gar nichts zu Fehlern geschrieben) soll ich ausgesagt haben, 
Fehler müsse man nicht beseitigen? Ich hab auch nichts zu, z.B., 
while-Schleifen geschrieben. Heißt das jetzt, dass ich sie generell für 
unnötig erachte?

Dussel schrieb:
> Manche Compiler warnen bei unbenutzten Variablen. Trotzdem ist ein
> Programm, das eine nicht benutzte Variable enthält, vollkommen korrekt
> und unterscheidet sich bei heutigen Compilern im Ergebnis nicht von
> einem Programm, das diese Variable nicht enthält.

Und ob es sich unterscheidet: Eine unbenutze Variable verschwendet 
Resourcen, der Compiler warnt zurecht davor. Und welchen Grund gäbe es, 
eine unbenutzte Variable im Code zu lassen? Welchen Vorteil hat man denn 
davon?

von Thomas E. (picalic)


Lesenswert?

M. K. schrieb:
> Eine unbenutze Variable verschwendet
> Resourcen,

Wenn der Compiler was taugt, merkt er, daß die Variable nicht benutzt 
ist und wird keine Recourcen dafür verschwenden!

von Yalu X. (yalu) (Moderator)


Lesenswert?

Thomas E. schrieb:
> M. K. schrieb:
>> Eine unbenutze Variable verschwendet
>> Resourcen,
>
> Wenn der Compiler was taugt, merkt er, daß die Variable nicht benutzt
> ist und wird keine Recourcen dafür verschwenden!

Und wenn es der Compiler nicht merkt, wird er auch keine Warnung dazu
ausgeben.

Die Warnung dient also einzig und allein dazu, dem Programmierer
folgendes mitzuteilen:

1
  Hey, es gibt doch sicher einen Grund, warum du hier die Variable xy
2
  definiert hast. Kann es sein, dass da noch ein Stück Programmcode
3
  fehlt, der diese Variable verwendet. Wenn ja, dann solltest du das
4
  Programm noch nicht verkaufen, sondern erst einmal zu Ende schreiben."

von nichtCler (Gast)


Lesenswert?

Thomas E. schrieb:
> M. K. schrieb:
>> Eine unbenutze Variable verschwendet
>> Resourcen,
>
> Wenn der Compiler was taugt, merkt er, daß die Variable nicht benutzt
> ist und wird keine Recourcen dafür verschwenden!

Oder er gibt statt einer Warnung einen Hinweis aus.

von Rolf M. (rmagnus)


Lesenswert?

M. K. schrieb:
> Sorry, aber so einen Unsinn hab ich schon lange nicht mehr gelesen. Nur
> weil ich nicht schrieb, dass man auch Fehler beseitigen soll (genauer:
> ich hab gar nichts zu Fehlern geschrieben) soll ich ausgesagt haben,
> Fehler müsse man nicht beseitigen?

Nein. Weil du gesagt hast, dass das der UNTERSCHIED zwischen Warnung 
und Fehler ist. Was ist daran denn so schwer zu begreifen?

> Ich hab auch nichts zu, z.B., while-Schleifen geschrieben. Heißt das
> jetzt, dass ich sie generell für unnötig erachte?

Wenn du gesagt hättest, dass der UNTERSCHIED zwischen while und goto 
für eine Endlosschleife ist, dass du goto dort für sinnvoll erachtest, 
dann hättest du das damit tastsächlich gesagt.

> Und ob es sich unterscheidet: Eine unbenutze Variable verschwendet
> Resourcen, der Compiler warnt zurecht davor. Und welchen Grund gäbe es,
> eine unbenutzte Variable im Code zu lassen? Welchen Vorteil hat man denn
> davon?

Nehmen wir ein anderes Beispiel: Ein unbenutzter Parameter erzeugt in 
gcc auch eine Warnung. Manchmal braucht man einen solchen aber, wenn die 
API es erfordert, z.B. wenn man eine Callback-Funktion definiert, die 
eben zwingend diesen Parameter haben muss. Oder wenn im Zuge der 
Weiterentwicklung der Parameter nicht mehr nötig ist, die API sich aber 
nicht ändern darf. Sowas passiert mir praktisch regelmäßig. Ein gängiger 
Weg, die Warnung zu unterbinden, sieht dann etwa so aus:
1
void sighandler(int sig)
2
{
3
    sig = sig;
4
    // ...
5
}
oder auch:
1
void sighandler(int sig)
2
{
3
    (void)sig;
4
    // ...
5
}

Da warnt der Compiler dann nicht mehr. Was in meinen Augen irgendwie 
schon weh tut. Man muss einen völlig sinnlosen Quatsch hinschreiben, nur 
um eine nutzlose Warnung wegzubekommen.
Alternativ kann man bei GCC mit __attribute__((unused)) auch eine 
Compiler-Erweiterung nutzen, um die Warnung loszuwerden.

Yalu X. schrieb:
> Die Warnung dient also einzig und allein dazu, dem Programmierer
> folgendes mitzuteilen:
>
>   Hey, es gibt doch sicher einen Grund, warum du hier die Variable xy
>   definiert hast. Kann es sein, dass da noch ein Stück Programmcode
>   fehlt, der diese Variable verwendet. Wenn ja, dann solltest du das
>   Programm noch nicht verkaufen, sondern erst einmal zu Ende schreiben."

Ja, mit anderen Worten: Der Compiler glaubt zu wissen, warum du das so 
gemacht hast und dass das so falsch ist. Wenn du aber einen guten Grund 
hast, musst du dir irgendeinen work-around für die falsche Warnung 
einfallen lassen.

nichtCler schrieb:
>> Wenn der Compiler was taugt, merkt er, daß die Variable nicht benutzt
>> ist und wird keine Recourcen dafür verschwenden!
>
> Oder er gibt statt einer Warnung einen Hinweis aus.

Was ist denn nun wieder der Unterschied zwischen einer Warnung und einem 
Hinweis? Und bei welchem Compiler gibt es sowas?

von nichtCler (Gast)


Lesenswert?

Rolf M. schrieb:
> nichtCler schrieb:
>>> Wenn der Compiler was taugt, merkt er, daß die Variable nicht benutzt
>>> ist und wird keine Recourcen dafür verschwenden!
>>
>> Oder er gibt statt einer Warnung einen Hinweis aus.
>
> Was ist denn nun wieder der Unterschied zwischen einer Warnung und einem
> Hinweis? Und bei welchem Compiler gibt es sowas?

https://de.wikipedia.org/wiki/Warnung
https://de.wikipedia.org/wiki/Hinweis

Ich kenne keinen Compiler der soviel taugt, daß er da einen Unterschied 
macht.

von Michael S. (rbs_phoenix)


Lesenswert?

W.S. schrieb:
> Bei diesem Konstrukt merkt der Compiler endlich (!), daß es nie und
> nimmer zurückgeht und hält die Fresse.

Er wird nur meckern, weil auch eine while(1) unterbrochen werden kann 
(mit break). Und in diesem Falle würde er dann auch zum Ende der Main 
gelangen. Wenn er aber erkennen soll, dass innerhalb der while(1) 
nirgends ein break; zu finden ist, dies aber nicht tut, darf man sich 
nicht über die Sprache und die Verwendung dessen Elemente beschweren, 
sondern über den Compiler.

Ob nun eine while(1) oder ein goto optisch und styleguide-mäßig sauberer 
ist, ist die eine (nicht beantwortbare) Frage. Die andere ist eine 
Funktion mit Rückgabewert kein return schenken zu wollen. Auch wenn es 
nie erreicht wird (genauer: erreicht werden soll), gehört es aus meiner 
Sicht immer dahin. Daher mache ich mir diese "Mühe" und schreibe ein 
return 0; hin, zusammen mit dem Kommentar, dass das return nie erreicht 
werden kann/soll und dass der Compiler ein void main() nicht akzeptiert.
Sonst guckt nachher jemand anderes mal rein und sucht sich ein Wolf, wo 
denn ein Wert zurückgegeben wird. Besonders wenn dieser nicht weiß, dass 
die main ein int-Rückgabewert haben MUSS.


Dussel schrieb:
> Das 'Schlimmste', das ich in dem Fall erlebt habe, war eine
> Warnung 'Unreachable Statement'. Wenn du so dünnhäutig bist, dass dich
> eine Warnung so fertig macht, kannst du auch Goto verwenden, aber das
> ist absolut nicht die Regel.

Bei Nutzung von Goto muss in diesem Fall aber ebenfalls die Warnung 
kommen, da der Befehl ebenfalls nie ausgeführt wird. Sollte dies aber 
nicht so sein, wäre das für mich ein Grund (zumindest bei diesem 
Compiler) niewieder ein goto zu verwenden. Wer weiß, welche Warnungen 
oder sogar Fehler er sonst noch übersieht. Außerdem wäre wohl ein 
anderer Compiler angebracht.

von Programmierer (Gast)


Lesenswert?

Michael S. schrieb:
> Daher mache ich mir diese "Mühe" und schreibe ein
> return 0; hin, zusammen mit dem Kommentar, dass das return nie erreicht
> werden kann/soll

Code hinschreiben der nicht erreicht werden kann, ist einfach nur 
mistiger Stil.

Es scheint einigen hier nicht klar zu sein, dass main() eben keine 
Return-Anweisung benötigt, aber sehr wohl mit dem Rückgabe-Typ "int" 
definiert werden muss.

Siehe C-Standard (ISO/IEC 9899:2011):
1
5.1.2.2.3 Program termination
2
3
If the return type of the main function is a type compatible
4
with int, a return from the initial call to the main function
5
is equivalent to calling the exit function with the value
6
returned by the main function as its argument; reaching 
7
the } that terminates the main function returns a value of 0.

Um es nochmals klar auszusprechen: Ein fehlendes "return" in "int 
main(...)" ist absolut identisch zu "return 0" bzw. zu "exit(0)"!

Einfach mal den Standard lesen und sich dran halten.

Nächstes Thema: Eine Funktion mit einem Rückgabe-Typ ungleich "void" und 
einer Endlosschleife ohne "break" und "continue" benötigt natürlich auch 
kein "return X" weil dieser Code selbstverständlich nie erreicht werden 
kann. Gute Compiler warnen genau vor dem nicht-erreichbaren Code!

von Mani W. (e-doc)


Lesenswert?

Vielleicht wäre statt "Goto" besser "Go Away" angebracht...

von Zeno (Gast)


Lesenswert?

Michael S. schrieb:
> Wenn er aber erkennen soll, dass innerhalb der while(1)
> nirgends ein break; zu finden ist, dies aber nicht tut, darf man sich
> nicht über die Sprache und die Verwendung dessen Elemente beschweren,
> sondern über den Compiler.

Genau das ist das klassische C-Problem. Jeder (Compilerhersteller) meint 
er müsse den Compiler neu erfinden und macht bei den Basics etwas 
anders. Der eine Compiler meckert wenn man main als void deklariert der 
andere (z.B. Xcode) gibt nur eine Warning aus. Der nächste verlangt 
zwingend das int vor main und ein return.. und so weiter und so weiter.

Oder man schaue sich mal die Deklaration der Interruptroutinen an - das 
macht jeder Compilerhersteller anders.

Zeno

von Rolf M. (rmagnus)


Lesenswert?

Programmierer schrieb:
> Siehe C-Standard (ISO/IEC 9899:2011):

> Um es nochmals klar auszusprechen: Ein fehlendes "return" in "int
> main(...)" ist absolut identisch zu "return 0" bzw. zu "exit(0)"!
>
> Einfach mal den Standard lesen und sich dran halten.

Ja, aber das ist wie gesagt nicht schon immer drin, sondern "erst" seit 
C99. Leider stecken viele Compiler (und Programmierer) noch im Jahr 1989 
fest, wo das noch nicht so war. Und es gilt auch nur für die Funktion 
main().

Mani W. schrieb:
> Vielleicht wäre statt "Goto" besser "Go Away" angebracht...

Es gibt ja auch noch den eigentlich viel cooleren umgekehrten Konstrukt 
names COMEFROM. Zwar nicht in C, aber in ein paar anderen Sprachen. Man 
schreibt also das Label an die Stelle, wo man springen will und am 
Sprungziel ein comefrom label.
Damit würde die Endlosschleife so aussehen:

comefrom label
    // schleifeninhalt
label:



Zeno schrieb:
> Genau das ist das klassische C-Problem. Jeder (Compilerhersteller) meint
> er müsse den Compiler neu erfinden und macht bei den Basics etwas
> anders. Der eine Compiler meckert wenn man main als void deklariert der
> andere (z.B. Xcode) gibt nur eine Warning aus. Der nächste verlangt
> zwingend das int vor main und ein return.. und so weiter und so weiter.

Deshalb gibt es eine ISO-Norm. Die sagt ganz klar, dass int immer 
funktionieren muss. Wer dann trotzdem stattdessen void benutzt, begibt 
sich eben in den Bereich der Compilerspezifika.
Natürlich ist es bei µCs so, dass main() normalerweise nie zurückkehrt 
und man das int nicht unbedingt bräuchte, aber µCs sind in der Hinsicht 
eben ein Spezialfall. int als Returntyp funktioniert dort aber auch.

: Bearbeitet durch User
von Mikro 7. (mikro77)


Lesenswert?

Rolf M. schrieb:

> oder auch:void sighandler(int sig)
> {
>     (void)sig;
>     // ...
> }

> Man muss einen völlig sinnlosen Quatsch hinschreiben, nur
> um eine nutzlose Warnung wegzubekommen.

Ob eine Meldung nutzlos ist oder nicht hängt wohl vom Betrachter ab.
1
sighandler(int)
2
{
3
    // ...
4
}

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.