Gibt es einen Befehl (bitte nur in C, da ich die Assembler Sprache nicht kenne), mit dem ich ungeachtet von Schleifen usw. zu einem bestimmten Punkt im Programm "springen" kann? Zum Beispiel, um bei bestimmen Bedingungen (wenn eine if-Abfrage wahr ist) wieder zum Anfang des Programms zu kommen und alle folgenden Befehle zu ignorieren? Danke und LG Peterson
Peter S. schrieb: > Gibt es einen Befehl (bitte nur in C, da ich die Assembler Sprache > nicht > kenne), mit dem ich ungeachtet von Schleifen usw. zu einem bestimmten > Punkt im Programm "springen" kann? Im Prinzip ja, aber ... setjmp/longjmp leo
Oder ein anderer weg ist..... Watchdog scharf machen, die einen Reset macht. Dann while(1); Der Rest kommt alleine Gruß Thomas
Wie immer bei solchen Fragen heißt die Gegenfrage: Warum? Oliver
Harry L. schrieb: > Gibt es: > break Mit 'break' steige ich aus einer 'while-Schleife' aus. Ein Unterprogramm verlasse ich mit 'return'. In beiden Fällen komme ich dahin zurück, von wo ich den Aufruf gemacht habe. Die Frage nach beliebig oder zum Anfang sehe ich damit als nicht gelöst an. Was meint Peter eigentlich mit "Anfang des Programms" - den Beginn der Hauptschleife?
Beitrag #5909778 wurde von einem Moderator gelöscht.
Beitrag #5909786 wurde von einem Moderator gelöscht.
Beitrag #5909788 wurde von einem Moderator gelöscht.
Oliver S. schrieb: > Wie immer bei solchen Fragen heißt die Gegenfrage: Warum? > > Oliver Warum willst Du das wissen? Beantworte doch einfach die Frage.
NichtWichtig schrieb: > Oliver S. schrieb: > Wie immer bei solchen Fragen heißt die Gegenfrage: Warum? > Oliver > > Warum willst Du das wissen? > > Beantworte doch einfach die Frage. Warum? Wenn man sich in einem Bereich nicht auskennt ist es unwahrscheinlich eine gute Lösung für ein Problem zu finden. Meist findet man dann schlechte Lösungen (man merkt allerdings nicht das die Lösung schlecht ist weil man die richtigen halt nicht kennt). Und dieser Person dann dabei zu helfen diese schlechte Lösung umzusetzen ist nicht wirklich eine Hilfe.
Peter S. schrieb: > von Schleifen usw. zu einem bestimmten Punkt im Programm "springen" > kann? goto wird oft in Kernel-Funktionen verwendet , da man im Gegensatz zu break, nicht nur Schleifen verlassen kann, sondern gezielt Labels (mit Marken gekennzeichnet Adressen) anspringen kann. Mit return kann man Schleifen in einem Unterprogramm verlassen indem man aus dem Unterprogramm selbst aussteigt.. Im Gegensatz zu goto wird beim Verlassen das Stack wieder in den ursprünglichen Zustand versetzt, dass heisst zuvor gesicherte Register wieder hergestellt.
Peter S. schrieb: > wieder zum Anfang des > Programms zu kommen und alle folgenden Befehle zu ignorieren? Dafür gibt es "Goto". Aber Verwendung von "Goto" ist nicht empfohlen.
Maxim B. schrieb: > Aber Verwendung von "Goto" ist nicht empfohlen. Genau, führt direkt in die Hölle!!!
Peter S. schrieb: > Gibt es einen Befehl (bitte nur in C, da ich die Assembler Sprache > nicht kenne), mit dem ich ungeachtet von Schleifen usw. zu einem > bestimmten Punkt im Programm "springen" kann? Es ist nicht möglich, in eine andere Funktion zu springen, ohne diese aufzurufen. Davon abgesehen wurden setjmp/longjmp bereits genannt. Zu guter Letzt gibt es noch eine gcc-Erweiterung, mit der man die Adresse eines Labels nehmen kann (void *ptr = &&labelname). Die kann man dann direkt anspringen (goto *ptr). Ist die Adresse außerhalb der aktuellen Funktion, passieren komische Dinge (kaputter Stack).
Hallo, GEKU schrieb:> > Mit welcher Begründung? Mit dieser Frage öffnest du gerade das Tor zur Hölle. rhf
Karl schrieb: > Maxim B. schrieb: >> Aber Verwendung von "Goto" ist nicht empfohlen. > > Genau, führt direkt in die Hölle!!! Aber nur mit Clang. Der derzeitige GCC meldet bei
1 | goto Hölle; |
mehrere Fehler, so dass die Fahrt in die Hölle gar nicht erst gestartet werden kann ;-) Das wird sich aber sicher in einer zukünftigen Version ändern.
:
Bearbeitet durch Moderator
Karl schrieb: > Genau, führt direkt in die Hölle!!! Ja, auf einem µC schon, aber in anderen Programmen, auf dem PC, ist das doch sicher noch üblich, wenn das auch als schlechter Stil angesehen wird. Der Zweck heiligt immer die Mittel.
1 | Zur Programmierung empfiehlt es sich, die break-, continue- und return-Anweisung der goto-Anweisung vorzuziehen, wann immer dies möglich ist. Da die break-Anweisung nur eine Ebene der Schleife beendet, ist möglicherweise eine goto-Anweisung erforderlich, um die Schleife aus einer tief verschachtelten Schleife heraus zu beenden. |
Wenn es sich aber um Programmierung von Mikrocontrollern handelt, sollte man so was tunlichst vermeiden.
:
Bearbeitet durch User
Yalu X. schrieb: > Aber nur mit Clang. Der derzeitige GCC meldet bei > > goto Hölle; > > mehrere Fehler, so dass die Fahrt in die Hölle gar nicht erst gestartet > werden kann ;-) ... und landet dann bei Wolfgang Petri. Hölle, Hölle, Hölle.
Wenn man mit einer Programmiersprache nicht umgehen kann, dann landet man im "Fegefeuer". Es gibt genügend andere Stolperfallen für Anfänger. Dazu zählt die Verwendung von Zeiger. Wer weiss, was bei einem Unterprogramm Aufruf passiert, z.B Sichern von Register und PC, sowie die Funktion des Stack bei der Anlage lokaler Variablen, der kann auch sicher mit Goto umgehen. Richtig, dass Goto nur eingesetzt werden, wenn andere Konstrukte scheitern oder das Programm unübersichtlich werden lassen.
GEKU schrieb: > andere Konstrukte scheitern oder das Programm unübersichtlich werden > lassen Z.B. wenn man aus einer Schleife aussteigen muss, ohne den Code nach dem Schleifenkonstrukt zu exekutieren. Dann braucht man eine "Hilfsvariable" um diesen Code zu überspringen. Hier kann mit Hilfe von Goto aus der Schleife heraus der Code übersprungen werden, ohne diese Hilfsvaraible zu benötigen. Es reicht eine Marke nach dem zu überspringenden Code zu setzen.
GEKU schrieb: > Z.B. wenn man aus einer Schleife aussteigen muss, ohne den Code nach > dem Schleifenkonstrukt zu exekutieren. "break" reicht nicht?
HGier mal ein kleines Beispiel, Peter S. schrieb: > um bei bestimmen Bedingungen (wenn eine if-Abfrage wahr ist) wieder > zum Anfang des Programms zu kommen und alle folgenden Befehle zu > ignorieren unter Verwendung des bereits vorgeschlagenen setjmp/longjmp:
1 | #include <stdio.h> |
2 | #include <setjmp.h> |
3 | |
4 | static jmp_buf env; |
5 | static int error = 1; |
6 | |
7 | void sub2(void) { |
8 | printf("sub2\n"); |
9 | if(error) |
10 | longjmp(env, 1); |
11 | printf("nie erreicht in sub2\n"); |
12 | }
|
13 | |
14 | void sub1(void) { |
15 | printf("sub1\n"); |
16 | sub2(); |
17 | printf("nie erreicht in sub1\n"); |
18 | }
|
19 | |
20 | int main(void) { |
21 | while(setjmp(env)) |
22 | printf("Neustart\n"); |
23 | |
24 | printf("main\n"); |
25 | sub1(); |
26 | printf("nie erreicht in main\n"); |
27 | }
|
Ausgabe:
1 | main |
2 | sub1 |
3 | sub2 |
4 | Neustart |
5 | main |
6 | sub1 |
7 | sub2 |
8 | Neustart |
9 | main |
10 | ... |
Maxim B. schrieb: > GEKU schrieb: >> Z.B. wenn man aus einer Schleife aussteigen muss, ohne den Code nach >> dem Schleifenkonstrukt zu exekutieren. > > "break" reicht nicht? Gibt kein 'doppelbreak' for zwei oder mehr Schleifen.
GEKU schrieb: > Im Gegensatz zu goto wird beim Verlassen das Stack wieder in den > ursprünglichen Zustand versetzt, Und was passiert beim goto?
NichtWichtig schrieb: > Oliver S. schrieb: >> Wie immer bei solchen Fragen heißt die Gegenfrage: Warum? >> >> Oliver > > Warum willst Du das wissen? Weil die Frage erstmal nach keiner guten Idee klingt und weil sie zu allgemein formuliert ist. Um eine optimale Antwort zu geben, muss man also erstmal wissen, wofür das ganze denn gebraucht wird. In der gefragten Allgemeinheit (von beliebiger Stelle im Programm an beliebige andere Stelle springen) wäre tatsächlich setjmp/longjmp am ehesten passend. Allerdings wird das tatsächlich nur äußerst selten gebraucht. Selbst langjährige C-Programmierer setzen das extrem selten bis gar nie ein. > Beantworte doch einfach die Frage. Welches Auto ist das beste für mich? Details zu Anforderungen und Wünschen verrate ich nicht. Bitte beantworte "einfach" diese Frage… F. F. schrieb: > Wenn es sich aber um Programmierung von Mikrocontrollern handelt, sollte > man so was tunlichst vermeiden. Warum sollte das auf einem µC anders sein als auf dem PC? GEKU schrieb: > Wer weiss, was bei einem Unterprogramm Aufruf passiert, z.B Sichern > von Register und PC, sowie die Funktion des Stack bei der Anlage lokaler > Variablen, der kann auch sicher mit Goto umgehen. Was haben die beiden denn miteinander zu tun? Register, Stack u.s.w sind Compiler-interne Implementationsdetails. goto ist ein Sprachkonstrukt, der vollkommen unabhängig davon definiert ist. > Richtig, dass Goto nur eingesetzt werden, wenn andere Konstrukte > scheitern oder das Programm unübersichtlich werden lassen. Ja. Da gibt es wenige Anwendungsfälle, aber es gibt sie. Maxim B. schrieb: > GEKU schrieb: >> Z.B. wenn man aus einer Schleife aussteigen muss, ohne den Code nach >> dem Schleifenkonstrukt zu exekutieren. > > "break" reicht nicht? break überspringt nur den Code in der Schleife, nicht den danach.
:
Bearbeitet durch User
A. S. schrieb: > GEKU schrieb: > Im Gegensatz zu goto wird beim Verlassen das Stack wieder in den > ursprünglichen Zustand versetzt, > > Und was passiert beim goto? Bei einem Sprung innerhalb der Funktion braucht mit den Stack nichts gemacht werden. Bei einem Sprung außerhalb der Funktion muss das Stack bereinigt werden. Das heisst, die zuvor am Stack gesicherten Register müssen wieder hergestellt, der gesicherte Programmcounter verworfen und der Stack Pointer auf den Wert vor dem Unterprogrammaufruf gesetzt werden. Letzteres verwirft auch die lokalen Variablen, die am Stack liegen. Diese Manipulationen lassen sich nur mit dem Inlineassambler, bei gesperrten Interrupts, bewerkstelligen. Daher sollten Gotos, die Labels außerhalb der eigenen Funktion anspringen tunlichst vermieden werden. Ausnahme Restart der Software. Aber auch hier gibt es bessere Methoden.
Rolf M. schrieb: > break überspringt nur den Code in der Schleife, nicht den danach so ist es. Aber vielleicht passiert in der Schleife etwas (z.B. Fehler beim Öffen einer Datei), dass die Abarbeitung des Codes unmittelbar nach dem Verlassen der Schleife falsch wäre (z.B. Lesen einer ungeöffneten Datei) .
NichtWichtig schrieb: > Beantworte doch einfach die Frage. Na dann:
1 | printf("Programm beendet. Bitte neu starten\n"); |
2 | exit(42); |
Oliver
Rolf M. schrieb: >> Beantworte doch einfach die Frage. > > Welches Auto ist das beste für mich? Details zu Anforderungen und > Wünschen verrate ich nicht. Bitte beantworte "einfach" diese Frage… Diese Analogie ist viel zu dumm! Ein Sprung und ein Auto daher nicht zu vergleichen.
GEKU schrieb: > sollten Gotos, die > Labels außerhalb der eigenen Funktion anspringen tunlichst vermieden > werden. Ausnahme Restart der Software. Noch nicht mal dann. Zumindest wenn du mit Restart meinst "Sprung an den Anfang von main()". Denn der Stack wird auch dabei nicht aufgeräumt respektive initialisiert. Das passiert außerhalb von main() [1] Jedes Mal, wenn man aus einer Funktion mit goto an den Anfang von main() springt, bleibt ein bißchen was auf dem Stack liegen. Mindestens die Rücksprungadresse; meist mehr, z.B. lokale Variablen der Funktion. Nach ein paar Zyklen (auf einem PC mit viel RAM ein paar Tausend Zyklen) läuft der Stack über und alles ist karpott. [1] genauer gesagt passiert das bevor main() von der C Laufzeitumgebung aufgerufen wird. Genauso wie die Initialisierung des Datensegments.
Rolf M. schrieb: > Was haben die beiden denn miteinander zu tun? Register, Stack u.s.w sind > Compiler-interne Implementationsdetails. goto ist ein Sprachkonstrukt, > der vollkommen unabhängig davon definiert ist. "goto ist ein Sprachkonstrukt, der vollkommen unabhängig davon definiert ist" genau das ist das Problem. Die Sprache C erlaubt viele gefährliche Konstrukte. Wen man Anfänger ist und nichts dazu lernen will, aus Fehlern lernt man bekanntlich, dann sollte man die "ausgetretenen Pfade" nicht verlassen oder eine halbwegs sichere Sprache, wie z.B. Java, verwenden. Ich bin kein Fan der Assembler-Programmierung, aber ein Programmierer in Hochsprache, sollte wissen, was Compiler aus dieser machen, und was auf der betroffenen Maschine (wichtig für Embedded Entwickler) abläuft.
NichtWichtig schrieb: > Beantworte doch einfach die Frage. Die lässt sich so direkt nicht beantworten. Der Programmzustand besteht nämlich nicht nur darin, in welcher Zeile (Instruktion) der Programmzähler gerade steht, sondern auch im Zustand der Variablen. Da kein "Verlauf" der Variablen aufgezeichnet wird, sind alte Variablenwerte verloren. Wenn man also an eine bestimmte "Stelle" im Programm springen möchte, was soll dann in den Variablen stehen? Die Dinge, die dort zuvor mal standen (jetzt aber weg sind)? Bestimmte fixe Werte? Wenn die angesprungene Stelle zurück kehrt (return), wo soll sie dann hingehen? Ohne diese Angaben kann man die Frage nicht beantworten. Vielleicht fällt beim Bestimmen dieser Angaben auch auf, dass ein solcher Sprung wenig praktikabel ist.
Yalu X. schrieb: > HGier mal ein kleines Beispiel, > ... > unter Verwendung des bereits vorgeschlagenen setjmp/longjmp: Hier mal mit einer kleinen Ergänzung:
1 | #include <stdio.h> |
2 | #include <setjmp.h> |
3 | #include <stdlib.h> |
4 | |
5 | static jmp_buf env; |
6 | static int error = 1; |
7 | static int startwert = 0; |
8 | |
9 | void sub2(void) { |
10 | printf("sub2\n"); |
11 | if(error) |
12 | longjmp(env, 1); |
13 | printf("nie erreicht in sub2\n"); |
14 | }
|
15 | |
16 | void sub1(void) { |
17 | printf("sub1\n"); |
18 | sub2(); |
19 | printf("nie erreicht in sub1\n"); |
20 | }
|
21 | |
22 | int main(void) { |
23 | while(setjmp(env)) |
24 | printf("Neustart, startwert = %d\n", startwert++); |
25 | printf("main\n"); |
26 | sub1(); |
27 | printf("nie erreicht in main\n"); |
28 | }
|
Ausgabe: main sub1 sub2 Neustart, startwert = 0 main sub1 sub2 Neustart, startwert = 1 main sub1 sub2 Neustart, startwert = 2 main sub1 sub2 Neustart, startwert = 3 main sub1 sub2 Neustart, startwert = 4 main sub1 sub2 Neustart, startwert = 5 main sub1 sub2 Neustart, startwert = 6 main sub1 sub2 Neustart, startwert = 7 main sub1 sub2 Neustart, startwert = 8 main sub1 sub2 Neustart, startwert = 9 ;) Oliver
:
Bearbeitet durch User
leo schrieb: > setjmp/longjmp Es gibt gute Gründe, warum erfahrene Programmierer diese nicht einsetzen. Gerade bei komplexen Programmen möchte man nur definierte Abläufe und kein wildes Umhergespringe. Sonst sieht man später selber nicht mehr durch, d.h. der Code wird fehleranfällig und schwer erweiterbar. Ich habe es mal ausprobiert und man kann beim AVR sogar aus Interrupts heraus springen, aber ich hatte bisher keine Notwendigkeit, es auch praktisch einzusetzen. D.h. es hätte nichts vereinfacht oder verbessert.
Axel S. schrieb: > Denn der Stack wird auch dabei nicht aufgeräumt respektive > initialisiert. Beim Sprung auf den Anfang von Main geht viel mehr schief. Selbst ein Sprung auf die Restart Adresse (erster Code, der nach einem Power On ausgefühert) bereinigt nicht alles. Z.B. Werden Register von embedded Komponenten nicht zurückgesetzt und initialisiert. Daher ist es besser einen Wachdog auszulösen, der einen HW Reset durchführt. Dann kann man nur hoffen, dass nicht nicht initaliserter Speicher verwendet wird, um Zustände über einen harten Reset hinüber zu retten. Windows verwendet sogar die Festplatte um dies zu tun.
Dumdi D. schrieb: > Maxim B. schrieb: > GEKU schrieb: > Z.B. wenn man aus einer Schleife aussteigen muss, ohne den Code nach > dem Schleifenkonstrukt zu exekutieren. > > "break" reicht nicht? > > Gibt kein 'doppelbreak' for zwei oder mehr Schleifen. Höchsten einen Trick. Man legt den verschachtelten Schleifenkonstrukt in ein eigenes Unterprogramm und verlässt die Schleife vorzeigen mit einem return. So kann man auch aus verschachtelten Schleifen sicher aussteigen. Auch ein goto wäre möglich, solange man die Programmebene nicht verlässt.
GEKU schrieb: > Auch ein goto wäre möglich, solange man die Programmebene nicht > verlässt. Würde ich nicht machen, da man auch lokale Variable in einem Block {} generieren kann und diese von eine GOTO bei einem Sprung aus dem Block vermutlich nicht bereinigt werden.
Was dann alles letztendlich wieder zu der Frage an den (wie erwartet nach der Fragestellung verschollenen) TO führt: Warum? Oliver
GEKU schrieb: > Würde ich nicht machen, da man auch lokale Variable in einem Block {} > generieren kann Das ist nur eine Frage der Sichtbarkeit. Denn in der Funktion darf sich der Stackpointer nicht ändern, sonst gibt es Probleme beim Variablenzugriff.
Der poster hat sich nicht mehr gemeldet, also weg mit dem Troll
тролхантэр schrieb: > Der poster hat sich nicht mehr gemeldet, ... Hat die üblichen Verdächtigen nicht gehindert den Thread vollzumachen.
Bernd schrieb: > Hat die üblichen Verdächtigen nicht gehindert den Thread vollzumachen. Sommerloch. Das dauert hier allerdings 12 Monate pro Jahr.
Rolf M. schrieb: > break überspringt nur den Code in der Schleife, nicht den danach. Man kann auch "return" benuzen. Dann ist man aus allen Schleifen dieser Funktion raus.
Peter D. schrieb: > Ich habe es mal ausprobiert und man kann beim AVR sogar aus Interrupts > heraus springen, aber ich hatte bisher keine Notwendigkeit, es auch > praktisch einzusetzen. D.h. es hätte nichts vereinfacht oder verbessert. Bin immer sehr an deinen Beiträgen hinsichtlich C interessiert. Und sehr interessant, dass das geht. Aber wie kommt man auf so eine Idee? Den Interrupt soll man doch sowieso so schnell wie möglich verlassen (so empfiehlt es zumindest die Literatur, die ich gelesen habe) und außerhalb der ISR weiter verarbeiten. Gibt es eigentlich ein Quasistandard für die Programmierung von Mikrocontroller? Also wie Programme aufgebaut sein sollten und Literatur darüber?
Beitrag #5910306 wurde von einem Moderator gelöscht.
Yalu X. schrieb: > Hier mal ein kleines Beispiel, > unter Verwendung des bereits vorgeschlagenen setjmp/longjmp: Wird der Stack in diesem Fall bereinigt? (Ich vermute mal nicht, da die Variable 'env' darauf hindeutet, dass die Zieladresse erst zur Laufzeit bestimmt wird, der Compiler eine notwendige Stackbereinigung also nicht einplanen kann.)
Mach schrieb: > (Ich vermute mal nicht Nachtrag: Ich vermute doch. Der Stackpointer kann ja bei setjmp einfach gesichert werden.
Mach schrieb: > Ich vermute mal nicht, Mach schrieb: > Nachtrag: Ich vermute doch. Vermuten, raten, schätzen, und glauben ist bei solchen Fragestellungen definitiv nicht zielführend. RTFM Oliver
Oliver S. schrieb: > Vermuten, raten, schätzen, und glauben ist bei solchen Fragestellungen > definitiv nicht zielführend. Es gibt doch so viele schöne Artikel, die alles ganz genau erklären. Neu war für mich, daß nur einfache Vergleiche zulässig sind. Man darf also nicht setjmp() einer Variablen zuweisen.
F. F. schrieb: > Aber wie kommt man auf so eine Idee? Z.B. Du hast eine Schleife, wo es auf ganz genaues Timing ankommt und die an vielen verschiedenen Stellen hängen bleiben kann. Dann kannst Du vorher einen Timerinterrupt aufsetzen, der sie abbrechen kann, ohne ständig die Abbruchbedingung testen zu müssen.
Peter S. schrieb: > Gibt es einen Befehl Goto habe ich bisher nur einmal gebraucht, weil ich zu faul war meinen eigentlichen Fehler zu korrigieren und statt dessen sauberen Code zu schreiben.
Karl schrieb: > Maxim B. schrieb: >> Aber Verwendung von "Goto" ist nicht empfohlen. > > Genau, führt direkt in die Hölle!! goto hell springt also direkt nach 0x666? F. F. schrieb: > ... und landet dann bei Wolfgang Petri. > Hölle, Hölle, Hölle. Das ist schlimmer als ein Schwarm Gotos. VIEL schlimmer.
GEKU schrieb: > Bei einem Sprung innerhalb der Funktion braucht mit den Stack nichts > gemacht werden. Ja > Bei einem Sprung außerhalb der Funktion muss das Stack bereinigt > werden. seit wann geht das mit goto in C? > ↑ ↓ 3.6.6.1 The goto statement > Constraints > > The identifier in a goto statement shall name a label located somewhere in the current function. > > Semantics > > A goto statement causes an unconditional jump to the statement prefixed by the named label in the current function.
Nachdenklicher schrieb: > goto hell springt also direkt nach 0x666? Woher weisst du, das die Addresse der Hölle in Base16 ist? Oder muss man vor 666 in jeder Basis aufpassen? Also sind all die Zahlen höllisch?
1 | 666, interpretiert als basis y, geschrieben in basis x: |
2 | |
3 | 7 8 9 10 11 12 13 14 15 16 base |
4 | |
5 | 666 526 420 342 291 246 204 1a6 17c 156 7 |
6 | 1164 666 536 438 369 306 279 234 1e3 1b6 8 |
7 | 1410 1042 666 546 457 396 330 2b0 266 222 9 |
8 | 1641 1232 820 666 556 476 3c3 358 2e6 29a 10 |
9 | 2220 1436 1076 798 666 566 495 410 383 31e 11 |
10 | 2514 1656 1256 942 787 666 576 4b4 42c 3ae 12 |
11 | 3126 2112 1450 1098 909 776 666 586 4d3 44a 13 |
12 | 3456 2362 1656 1266 a51 896 765 666 596 4f2 14 |
13 | 4134 2646 1876 1446 10a5 a06 873 754 666 5a6 15 |
14 | 4530 3146 2220 1638 125a b46 990 850 743 666 16 |
Oliver S. schrieb: > Vermuten, raten, schätzen, und glauben ist bei solchen Fragestellungen > definitiv nicht zielführend. Halt dich doch dem Forum fern, wenn du kein Bock auf Kommunikation hast. Natuerlich koennte ichs nachschauen, die Frage (und Antwort darauf) ist aber vielleicht (vermutlich~) auch fuer andere interessant. Zumal es da auch um Compiler-Internas geht, wie wird der Stack aufgeraeumt. Und wenn das mittels longjmp geht, koennte der Compiler das auch fuer Goto erledigen. Also Spruenge ueber Funktionsgrenzen hinweg erlauben und trotzdem den Stack sauber halten.
F. F. schrieb: > Also wie Programme aufgebaut sein sollten und Literatur darüber? Dieses Buch kann ich nur empfehlen.
als gute Gründe für die Verwendung von Goto gibt es: - in der Kantine alleine an einem Tisch ist schön ruhig - Der Titel "schlechtester Programmierer es Monats" ist besser als kein Titel - man kann den Kollegen der die Funktion verwenden wird nicht leider - letzten Monat gab es kein Gehalt - Kündigung ist schon abgeschickt - ...
Mach schrieb: > Zumal es da auch um Compiler-Internas geht, wie wird der Stack > aufgeraeumt. > Und wenn das mittels longjmp geht, koennte der Compiler das auch fuer > Goto erledigen. Also Spruenge ueber Funktionsgrenzen hinweg erlauben und > trotzdem den Stack sauber halten. Da es hier aber nicht um irgend eine hypothetische Programmiersprache, sondern ganz konkret um C geht, kommt es nicht drauf an, was alles sein könnte, sondern nur, was die Sprachdefinition dazu sagt. Compilerintenas haben damit nur so viel zu tun, als daß die Compiler den Sprachstandard zu implemetieren haben. goto in C springt ohne jede sonstige Aktionen zum Sprungziel, und das schon seit Anbeginn der C-Zeitrechnung. Oliver
Oliver S. schrieb: > goto in C springt ohne jede sonstige Aktionen zum Sprungziel, und das > schon seit Anbeginn der C-Zeitrechnung. Genau so ist es. Ums Stack muss sich der Programmierer kümmern..
GEKU schrieb: > F. F. schrieb: >> Also wie Programme aufgebaut sein sollten und Literatur darüber? > > Dieses Buch kann ich nur empfehlen. Danke!
Goto als Vorwärtssprung innerhalb der gleichen Funktion ist durchaus legitim und habe ich auch häufiger gemacht, um wartbaren und lesbaren Code zu erhalten der mit allen anderen Konstrukten wie Kraut und Rüben aussah. Zum Herausspringen aus mehreren verschachtelten Schleifen, ohne sich irgendwelche Abbruch-Variablen zu merken. Parserfunktionen sind solche Konstrukte, die bei einem Fehler möglichst schnell und zielgerichtet abbrechen sollen. Dort macht ein Vorwärtssprung aus der untersten Schleifenebene an das Ende der Funktion durchaus Sinn. Goto ist per se kein schlechtes Konstrukt, es verleitet nur unerfahrene Programmierer es zu misbrauchen. Fakt ist aber auch, dass man auch ohne Goto Code schreiben kann, der genau die gleiche Funktionalität bietet. Ob der dann so sauber aussieht, steht auf einem anderen Blatt. Viele Grüße! Sven
Sven L. schrieb: > Goto ist per se kein schlechtes Konstrukt, es verleitet nur unerfahrene > Programmierer es zu misbrauchen. Danke! Teil der Sprachstandards, aber alle brechen in Tränen aus wenn man es verwendet. Also ob man nicht auch ohne goto unleserlichen Bockmist schreiben könnte.
Peter S. schrieb: > Zum Beispiel, um bei bestimmen > Bedingungen (wenn eine if-Abfrage wahr ist) wieder zum Anfang des > Programms zu kommen und alle folgenden Befehle zu ignorieren? Was Du brauchst, ist vor allem mal eine vernünftige Programmstruktur anstalle Deines Kraut&Rüben-Verhaus, dann stellt sich diese Frage gar nicht erst.
Michael K. schrieb: > Teil der Sprachstandards, aber alle brechen in Tränen aus wenn man es > verwendet. Man muss ja nicht alle Sprachkonstrukte benutzen. Ich stehe z.B, immer noch mit Templates auf Kriegsfuß - egal, ich kann auch ohne sie programmieren. Oder Lambda Ausdrücke - ein paar beeindruckende Beispiele habe ich gesehen. Die meisten Anwendungen lesen sich für mich jedoch wie Strickmuster.
Mach schrieb: > Yalu X. schrieb: >> Hier mal ein kleines Beispiel, >> unter Verwendung des bereits vorgeschlagenen setjmp/longjmp: > > Wird der Stack in diesem Fall bereinigt? Ja. Peter D. schrieb: > leo schrieb: >> setjmp/longjmp > > Es gibt gute Gründe, warum erfahrene Programmierer diese nicht > einsetzen. Erfahrene Programmierer setzen setjmp/longjmp (wie auch goto) genau dort ein, wo es sinnvoll ist :) Peter D. schrieb: > Neu war für mich, daß nur einfache Vergleiche zulässig sind. Man darf > also nicht setjmp() einer Variablen zuweisen. Das darf man schon. Es ist aber gängige Praxis, direkt nach dem Aufruf von setjmp zu verzweigen, weswegen man sich eine zusätzliche Variable sparen kann.
MaWin schrieb: > Diese Analogie ist viel zu dumm! Merke: Nicht alles, was du nicht verstehst, ist dumm. Maxim B. schrieb: > Rolf M. schrieb: >> break überspringt nur den Code in der Schleife, nicht den danach. > > Man kann auch "return" benuzen. Dann ist man aus allen Schleifen dieser > Funktion raus. Dann ist man aber gleich komplett aus der Funktion raus. Außerdem hatten wir letztens erst eine Diskussion dazu, ob es guter Stil ist, kreuz und quer in der Funktion returns zu verteilen. Spätestens wenn du noch vor dem Verlassen irgendwas aufräumen musst, wird's unschön. Mach schrieb: > Mach schrieb: >> (Ich vermute mal nicht > Nachtrag: Ich vermute doch. Der Stackpointer kann ja bei setjmp einfach > gesichert werden. Genau deshalb gibt's ja setjmp. Volle schrieb: > als gute Gründe für die Verwendung von Goto gibt es: Schon witzig, wie manche geradezu dazu indoktriniert wurden, goto blind zu hassen, statt das Ganze nüchtern und technisch zu betrachten und es einfach da (und nur da) zu nutzen, wo es nützlich ist - so wie man das mit anderen Sprachkonstrukten auch tut.
GEKU schrieb: > Oliver S. schrieb: >> goto in C springt ohne jede sonstige Aktionen zum Sprungziel, und das >> schon seit Anbeginn der C-Zeitrechnung. > > Genau so ist es. Ums Stack muss sich der Programmierer kümmern.. Nein, um den kümmert sich der Compiler. Mit goto kann man die Funktion nicht verlassen, siehe A. S. schrieb: >> ↑ ↓ 3.6.6.1 The goto statement >> Constraints >> The identifier in a goto statement shall name a label located somewhere >> in the current function. >> Semantics >> A goto statement causes an unconditional jump to the statement prefixed >> by the named label in the current function.
hier wird ja viel phantasiert und im kreis gedreht ... und unsinn zu setjmp/longjmp verbreitet. setjmp/longjmp in c ist NICHT ein "goto" zu zielen ausserhalb einer aktiven funktion sondern ein GO BACK zu einem beliebigen sprungziel das vorher schon mal besucht wurde und mit setjmp markiert wurde! setjmp speichert also den zustand zum zeitpunkt des besuches/aufrufes und dieser wird später rekonstruiert, wenn dorthin zurückgesprungen wird. UND goto ist ein nützlices kontrukt um z.b. eine eihheitliche fehlerbehandlung zu realisieren, auch in parsern wird goto oft verwendet oder zur laufzeitoptimiereung in echtzeitkritschen bereichen. mt
Rolf M. schrieb: > wie manche geradezu dazu indoktriniert wurden, goto blind > zu hassen, Das machen die selber. Selbstsuggestion. Könnten ja auch nachdenken... Ist aber zu unbequem, dann müsste man ja evtl. Einsicht zeigen. Nee... Die dogmatische Sicht, macht das Leben einfacher. Da gibts wenigstens ein klares Gut und Böse. ------------ Goto hat seinen Ruf erlangt, als z.B. Basic noch keine Subroutinen und/oder benannte Lables kannte. Diese wirklich schlimme Zeit/Erfahrung auf C/C++ zu projizieren, ist keine intellektuelle Glanzleistung. In den C artigen Sprachen gab es nie die Notwendigkeit für einen extensiven Goto Gebrauch.
Weil sich alles, was man mit goto machen konnte, auch mit anderen Konstrukten machen lässt.
1 | switch(N) { |
2 | case 1: |
3 | if(something) { |
4 | case 2: return 0; |
5 | } |
6 | default: |
7 | return 1; |
8 | } |
:
Bearbeitet durch User
NichtWichtig schrieb: > Oliver S. schrieb: > Wie immer bei solchen Fragen heißt die Gegenfrage: Warum? > Oliver > > Warum willst Du das wissen? > > Beantworte doch einfach die Frage. Das ist hier Gang und Gebe. Man kann hier keine simple Frage mehr stellen, ohne dass man gleich das ganze Projekt oder Vorhaben im Detail erlautert
max schrieb: > an kann hier keine simple Frage mehr stellen, ohne dass man gleich das > ganze Projekt oder Vorhaben im Detail erlautert Doch. Kann man. Aber die Frage ist nicht simple, und sehr vermutlich auch nicht sinnvoll, schon gar nicht bei dem offensichtlichen Anfängerstatus des TO. Und daher: Was genau an http://xyproblem.info/ hast du nicht verstanden? Oliver
Heiko L. schrieb: > Weil sich alles, was man mit goto machen konnte, auch mit anderen > Konstrukten machen lässt. Es gibt vieles, das man durch andere Konstrukte ersetzen kann. Das heißt noch lange nicht, dass der Code dadurch gezwungenermaßen besser wird.
Beitrag #5911983 wurde von einem Moderator gelöscht.
GEKU schrieb: >> Auch ein goto wäre möglich, solange man >> die Programmebene nicht verlässt. > > Würde ich nicht machen, da man auch lokale Variable > in einem Block {} generieren kann und diese von eine > GOTO bei einem Sprung aus dem Block vermutlich nicht > bereinigt werden. Du vermutest falsch. Lerne bitte C. GEKU schrieb: >> goto in C springt ohne jede sonstige Aktionen zum Sprungziel, >> und das schon seit Anbeginn der C-Zeitrechnung. > > Genau so ist es. Ums Stack muss sich der Programmierer kümmern.. Das ist falsch[*]. Man kann nicht mit "goto" aus einer Funktion herausspringen[*]. Lerne bitte C. [*] Ausnahme: computed goto, aber das ist eine GCC-Erweiterung.
S. R. schrieb: > Du vermutest falsch. Lerne bitte C. Warum bittest Du ihn, das zu tun? Warum sollte sich jemand sein Vermögen, logisch denken zu können mit so einem Rotz kaputt machen?
Bei der ganzen Diskussion um "goto" habe ich mir überlegt, ob es einen Grund geben könnte ganz aus dem Programmablauf auf einem Mikrocontroller aus zu steigen, sodass er wirklich nichts mehr macht. Hat schon einmal jemand so was gemacht und gäbe es relevante Gründe (Sicherheitsabbruch) das zu tun?
F. F. schrieb: > ob es einen > Grund geben könnte ganz aus dem Programmablauf auf einem Mikrocontroller > aus zu steigen, sodass er wirklich nichts mehr macht. Wo willst du denn hin springen, ins Nirvana? Wenn der Mikrocontroller nichts mehr machen soll, musst du alle I/O Funktionen stoppen (Timer, DMA, etc.) und dann in eine Endlosschleife gehen. Genau so macht es auch dein Windows, wenn du es auf einem Rechner herunter fährst, der sich nicht selbst aus schalten kann.
Ja klar, so würde ich es machen. Mir kam da halt der Gedanke an einen Notfallausstieg. Aber auch da gibt es andere Wege.
F. F. schrieb: > Bei der ganzen Diskussion um "goto" habe ich mir überlegt, ob es einen > Grund geben könnte ganz aus dem Programmablauf auf einem Mikrocontroller > aus zu steigen, sodass er wirklich nichts mehr macht. In der Tuningszene gibt es Geräte um das Motorsteuergerät zu tunen. Damit nun nicht jemand sein Gerät nach getaner Arbeit weiter verkauft, führt dieses als letztes Kommando ein Full-Erase durch. Danach rennt die CPU nur noch durch den gelöschten Flash und führt 0xFF aus.
Stefanus F. schrieb: > Wenn der Mikrocontroller nichts mehr machen soll, musst du alle I/O > Funktionen stoppen (Timer, DMA, etc.) und dann in eine Endlosschleife > gehen. Das ist aber fast regelmäßig das Gegenteil dessen, was man von einem µC haben will. Der soll sich nicht sang- und klanglos aufhängen, sondern wenigstens einen Restart durchführen. Ob da der Watchdog als Brutalknüppel die richtige Wahl ist, halte ich für diskussionswürdig. Dezenter geht's auch, indem man im Startupcode einen Einsprung für einen Warmstart vorsieht und beim Setup des ganzen µC eben auch den Fall bedenkt, daß der Setup eben nicht immer darauf bauen darf, daß alle Hardware im Defaultzustand nach Reset vorliegt. W.S.
Stefanus F. schrieb: > F. F. schrieb: >> ob es einen >> Grund geben könnte ganz aus dem Programmablauf auf einem Mikrocontroller >> aus zu steigen, sodass er wirklich nichts mehr macht. > > Wo willst du denn hin springen, ins Nirvana? In die wirkliche Welt natürlich. Wie am Ende von 13th Floor.
:
Bearbeitet durch User
GEKU schrieb: > Axel S. schrieb: >> Denn der Stack wird auch dabei nicht aufgeräumt respektive >> initialisiert. > > Beim Sprung auf den Anfang von Main geht viel mehr schief. Das kann ich bestätigen. Gesprungen, unglücklich aufgekommen, noch versucht, am Stackpointer festzuhalten -> Der ist umgefallen, alle Rücksprungadressen lagen kreuz und quer -> ausgerutscht und Sprunggelenk gebrochen.
F. F. schrieb: > Also wie Programme aufgebaut sein sollten und Literatur darüber? Programmierstil, Fallstricke, Module http://www.netzmafia.de/skripten/programmieren/ad13.html#10.1 Zu Empfehlen, kostet nichts!
Feststeller schrieb: > S. R. schrieb: > >> Du vermutest falsch. Lerne bitte C. > > Warum bittest Du ihn, das zu tun? Weil es keinen Sinn hat, in so einer Diskussion mit Vermutungen und Spekulationen um sich zu werfen. F. F. schrieb: > Bei der ganzen Diskussion um "goto" habe ich mir überlegt, ob es einen > Grund geben könnte ganz aus dem Programmablauf auf einem Mikrocontroller > aus zu steigen, sodass er wirklich nichts mehr macht. > Hat schon einmal jemand so was gemacht und gäbe es relevante Gründe > (Sicherheitsabbruch) das zu tun? Kann z.B. vorkommen, wenn ein schwerwiegender Fehler aufgetreten ist. Dann springt man in eine Routine, die hoffentlich noch irgendeine Meldung rausbekommt und dann in eine Endlosschleife geht, bis der Watchdog dann automatisch den ganzen Prozessor neu startet. Arduino Fanboy D. schrieb: > Ja! > > Dafür wurde exit() erfunden. Um µCs ins Nirvana zu schicken? Eher nicht.
:
Bearbeitet durch User
Rolf M. schrieb: >> Dafür wurde exit() erfunden. > > Um µCs ins Nirvana zu schicken? Eher nicht. Naja, exit() ist beim µC, was Du draus machst. Es ist halt Konvention, auch wenn Du FatalError() oder sonstwas festlegen kannst.
A. S. schrieb: > Naja, Eigentlich hatte ich gedacht: "Lass ihn!" Hat er doch eine so schöne Gelegenheit gefunden mir einen einzuschenken... https://www.microchip.com/webdoc/AVRLibcReferenceManual/group__avr__stdlib_1ga137096a48cc0c731052cadfb69c39b34.html Ich finde, das ist doch schon eine Form von Nirvana. evtl. vielleicht gibts unterschiedliche Vorstellungen davon, was "µC im Nirvana" bedeutet. Wenn man mehr erreichen möchte, z.B. PWMs abschalten, sollte man das vor dem exit() tun(C), oder es den Destruktoren überlassen(C++). Ok, ok, das gilt jetzt erstmal nur für AVRs. Aber immerhin sind das µC !
Arduino Fanboy D. schrieb: > Aber immerhin sind das µC ! Ich hab nicht behauptet, dass man es auf µCs nicht einsetzen kann, sondern lediglich der Behauptung widersprochen, dass es dafür gemacht sei.
F. F. schrieb: > habe ich mir überlegt, ob es einen > Grund geben könnte ganz aus dem Programmablauf auf einem Mikrocontroller > aus zu steigen, sodass er wirklich nichts mehr macht. Arduino Fanboy D. schrieb: > Ja! > > Dafür wurde exit() erfunden. Rolf M. schrieb: > sondern lediglich der Behauptung widersprochen, dass es dafür gemacht > sei. exit() wurde erfunden, um aus einem laufendem Programm aus zu steigen. Oder, was sind die Wurzeln/Zweck des exit()? Dass es auf einem µC etwas anders wirkt, als unter einem OS getriebenem System, sollte einen jetzt nicht so dolle verwundern, denke ich mal. In Verbindung mit dem/einem WDT ist das eine recht zuverlässige Nummer, auch für den TO.
Arduino Fanboy D. schrieb: > In Verbindung mit dem/einem WDT ist das eine recht zuverlässige Nummer, > auch für den TO. D.H. ich schicke die MCU nach Irgendwo und vertraue darauf das der Compiler das schon zu irgendwas sinnvollem komplettieren wird. Grelle Idee aber warum? Wenn der anhalten soll, dann halte ich den an. Wenn der resetten soll, dann löse ich einen Software Reset aus. Und warum sollte der TO einen WDT zielführend einsetzen können, wenn das schon geschätzen 50% der eher nebenbei Programmierenden erheblich zu hoch ist?
Michael K. schrieb: > Wenn der resetten soll, dann löse ich einen Software Reset aus. Wie willst du das tun, wenn der betreffende µC keine Möglichkeit kennt? z.B. die AVR Michael K. schrieb: > D.H. ich schicke die MCU nach Irgendwo und vertraue darauf das der > Compiler das schon zu irgendwas sinnvollem komplettieren wird. Natürlich! Ist es doch genau das, was "Programmierer" tagtäglich tun. Vertrauen, dass der Kompiler genau das tut, was man sich von ihm wünscht. Was exit() tut, ist in der AVR LibC definiert! Oder stellst du alles in Frage, was diese Lib bietet? Wie der WDT agiert, ist im Datenblatt des µC beschrieben. Glaubst du dem auch nicht? Wenn du min. eine der Fragen mit JA beantwortest, dann wäre vielleicht auch dieses was für dich: https://youtu.be/AXu5zRoUShw
Arduino Fanboy D. schrieb: > Was exit() tut, ist in der AVR LibC definiert! Toll wenn man nur diese eine MCU kennt. Arduino Fanboy D. schrieb: > Wenn du min. eine der Fragen mit JA beantwortest, dann wäre vielleicht > auch dieses was für dich: > Youtube-Video "Die Globus-Religion Okay, Du bist ein Idiot. Sorry, habe ich nicht gewusst.
Michael K. schrieb: > Toll wenn man nur diese eine MCU kennt. Dass sich diese (exit() und WDT) Aussage ausschließlich um AVR drehte, ist dir nicht aufgefallen? Scheinbar nein. Oder ist es dir nur egal? Michael K. schrieb: > Okay, Du bist ein Idiot. Vielleicht solltest mal in einen Spiegel schauen, und diese Einschätzung drei mal laut wiederholen. --- Oder anders? Warum bist du an einer solchen Auseinandersetzung so interessiert?
Michael K. schrieb: > Toll wenn man nur diese eine MCU kennt. Die MCU ist doch völlig egal. Wenn es eine lib gibt, die eine Funktion exit enthält, sollte auch dokumentiert sein, was die macht. Ob man die dann sinnvoll verwenden kann, bleibt dem geneigten Programmierer überlassen. Oliver
Oliver S. schrieb: > Michael K. schrieb: >> Toll wenn man nur diese eine MCU kennt. > > Die MCU ist doch völlig egal. Wenn es eine lib gibt, die eine Funktion > exit enthält, sollte auch dokumentiert sein, was die macht. Wenn ich in eine Endlosschleife rennen will, kann ich auch einfach eine Endlosschleife hinschreiben, statt erst in der Doku nachzuschauen, ob bei der verwendeten libc exit() das zufällig auch tut.
:
Bearbeitet durch User
GEKU schrieb: > GEKU schrieb: >> Auch ein goto wäre möglich, solange man die Programmebene nicht >> verlässt. > > Würde ich nicht machen, da man auch lokale Variable in einem Block {} > generieren kann und diese von eine GOTO bei einem Sprung aus dem Block > vermutlich nicht bereinigt werden. Mit der Betonung auf "vermutlich". Hier ein Beispiel, wie eine Bereinigung stattfindet:
1 | void f (char*); |
2 | |
3 | char func (char a, unsigned char b) |
4 | {
|
5 | if (a < 'P') |
6 | {
|
7 | char c[b]; |
8 | f (c); |
9 | if (a < 'M') |
10 | goto end; |
11 | f (c); |
12 | }
|
13 | a++; |
14 | end:
|
15 | return a; |
16 | }
|
Abhängig von a wird Array c[] initialisiert, dessen Größe erst zur Laufzeit bekannt ist. f() dient nur der Verwendung von c[]. Je nach a wird der Block vorzeitig verlassen und ans Ende der Funktion gesprungen, und c[] wird danach im Block noch 1x verwendet, kann also nicht vor dem goto aufgeräumt werden. Code (avr-gcc): c[] wird in Zeile :12 auf den Stack angelegt, der Wert von SP wird in R14/15 gemerkt (Zeilennummern siehe asm-Kommentar). Nach dem goto-Vergleich in :14 wird in beiden Pfaden SP wieder aus R14/15 hergestellt.
1 | func: |
2 | push r12 |
3 | push r13 |
4 | push r14 |
5 | push r15 |
6 | push r17 |
7 | /* prologue: function */ |
8 | mov r17,r24 ; a, a |
9 | ; foo.c:21: } |
10 | in r14,__SP_L__ ; tmp55 |
11 | in r15,__SP_H__ ; tmp55 |
12 | ; foo.c:10: if (a < 'P') |
13 | cpi r24,lo8(80) ; a, |
14 | brge .L2 |
15 | ; foo.c:12: char c[b]; |
16 | in r24,__SP_L__ |
17 | in r25,__SP_H__ |
18 | sub r24,r22 ; , b |
19 | sbc r25,__zero_reg__ |
20 | out __SP_L__,r24 |
21 | out __SP_H__,r25 |
22 | adiw r24,1 |
23 | movw r12,r24 ; tmp52, |
24 | ; foo.c:13: f (c); |
25 | call f |
26 | ; foo.c:14: if (a < 'M') |
27 | cpi r17,lo8(77) ; a, |
28 | brge .L3 |
29 | out __SP_L__,r14 ; tmp55 |
30 | out __SP_H__,r15 ; tmp55 |
31 | .L4: |
32 | ; foo.c:21: } |
33 | mov r24,r17 ; , a |
34 | /* epilogue start */ |
35 | pop r17 |
36 | pop r15 |
37 | pop r14 |
38 | pop r13 |
39 | pop r12 |
40 | ret |
41 | .L3: |
42 | ; foo.c:16: f (c); |
43 | movw r24,r12 ; , tmp52 |
44 | call f |
45 | out __SP_L__,r14 ; tmp55 |
46 | out __SP_H__,r15 ; tmp55 |
47 | .L2: |
48 | ; foo.c:18: a++; |
49 | subi r17,lo8(-(1)) ; a, |
50 | rjmp .L4 |
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.