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
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.
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.
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.
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
> 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.
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.
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)
µ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.
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
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?
> 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.
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
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.
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.
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.
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.
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.
> 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.
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?
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/
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.
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?
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.
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 ?
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.
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.
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. ;-)
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.
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.
Eine Renaissance des Goto? OMG!
Rein syntaktisch ist Goto in C vollkommen überflüssig. Praktisch ist es
nur in EXTREM wenigen Situationen gerechtfertigt.
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.
> 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.
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).
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.
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?
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.
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?
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.
> 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.
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?
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.
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.
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) ?
$ 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
Μα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.
Μα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'.
Μα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.
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;"
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.
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.
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]
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.
@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"?
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
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 ...
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?
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
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.
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.
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?
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.
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.
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.
>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.
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.
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
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.
> 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.
@ 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.
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.
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?
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.
@ 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 ;-)
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;
}
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.
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.
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;
}
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).
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?
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
.
.
..
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.
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
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?
@ 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)
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.
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.
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.
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.
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!
@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.
@ 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.
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:
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.
>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
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
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
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.
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.
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.
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:
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:
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.
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
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...
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.
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.
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. ;-)
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.
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.
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
gotoAnfang;
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
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).
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.
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.
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:
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...
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.
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
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
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 …
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" " };-)
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? ;-)
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.
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.
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. :-)
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.
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.
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
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.
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
intmain(void)
2
{// initialisierungen
3
....
4
5
while(1)
6
{// irgendwelcher Inhalt
7
...
8
}
9
return0;
10
}
weil er sonst vom Compiler angepfiffen wird. Selber schon unzählige Male
erlebt.
Wie also geht's besser? So:
1
intmain(void)
2
{// initialisierungen
3
....
4
5
elleweil:
6
// irgendwelcher Inhalt
7
...
8
gotoelleweil;
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
intblabla(.....)
2
{intretcode;
3
4
Aktion1...// z.B. File öffnen
5
retcode=1;
6
if(!Kondition1())gotoraus_hier;
7
8
Aktion2...// z.B. parsen
9
retcode=2;
10
if(!Kondition2())gotoraus_hier;
11
12
Aktion2...// z.B. noch ne Datei öffnen
13
nochmalsowaswieoben
14
15
retcode=Is_OK;
16
MachSonstwas...
17
18
raus_hier:
19
RäumeAuf,SchließeAb...
20
returnRetCode;
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.
@ 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.
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.
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.
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
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?
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
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.
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.
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.
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.)
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.)
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.
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
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.
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
intmain(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
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
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?
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.
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
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.
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.
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.
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?
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.
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.
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.
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.
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
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 :-)
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
voidmain(void)
2
{
3
....
4
}
Dabei ist es egal ob man als Endlosschleife while(1), for(;;) oder
W.S.'s goto nimmt.
Zeno
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
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
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
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
intmain(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?
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?
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!
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."
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.
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
voidsighandler(intsig)
2
{
3
sig=sig;
4
// ...
5
}
oder auch:
1
voidsighandler(intsig)
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?
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/Warnunghttps://de.wikipedia.org/wiki/Hinweis
Ich kenne keinen Compiler der soviel taugt, daß er da einen Unterschied
macht.
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.
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!
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
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.
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.