In C aus Programm herausspringen

OP #5909745
Lesenswert?

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
Gast #5909777
Lesenswert?

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.
Gast #5909831
Lesenswert?

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.
Gast #5909835
Lesenswert?

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.
#5909845
Lesenswert?

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).
Moderator #5909859
Lesenswert?

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.
#5909860
Lesenswert?

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.
Gast #5909868
Lesenswert?

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.
Gast #5909884
Lesenswert?

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.
Moderator #5909898
Lesenswert?

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
...
#5910040
Lesenswert?

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.
Gast #5910044
Lesenswert?

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.
Gast #5910060
Lesenswert?

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) .
Gast #5910070
Lesenswert?

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.
#5910071
Lesenswert?

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.
Gast #5910073
Lesenswert?

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.
Gast #5910076
Lesenswert?

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.
#5910080
Lesenswert?

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
#5910083
Lesenswert?

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.
Gast #5910088
Lesenswert?

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.
Gast #5910102
Lesenswert?

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.
Gast #5910114
Lesenswert?

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.
#5910303
Lesenswert?

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.
Gast #5910328
Lesenswert?

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.)
Gast #5910462
Lesenswert?

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.
Gast #5910486
Lesenswert?

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
Gast #5910524
Lesenswert?

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.
Gast #5910540
Lesenswert?

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
- ...
#5910547
Lesenswert?

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
#5910673
Lesenswert?

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
Gast #5910684
Lesenswert?

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.
Gast #5910744
Lesenswert?

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.
Gast #5910764
Lesenswert?

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.
Moderator #5910768
Lesenswert?

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.
#5910950
Lesenswert?

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.
#5910993
Lesenswert?

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.
(Firma: @home) #5911251
Lesenswert?

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
Gast #5911301
Lesenswert?

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.
Gast #5911390
Lesenswert?

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
Beitrag #5911983 wurde von einem Moderator gelöscht.
#5912281
Lesenswert?

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.
#5912477
Lesenswert?

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?
Gast #5912571
Lesenswert?

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.
#5912623
Lesenswert?

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.
Gast #5912656
Lesenswert?

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.
Gast #5912786
Lesenswert?

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.
#5913034
Lesenswert?

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.
Gast #5913186
Lesenswert?

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 !
Gast #5913242
Lesenswert?

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.
Gast #5915460
Lesenswert?

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?
Gast #5915497
Lesenswert?

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
Gast #5915699
Lesenswert?

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?
#5916018
Lesenswert?

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.
Persönliche Seite #5916072
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren