Forum: Compiler & IDEs While(1) - Break und Continue


von ichdu (Gast)


Lesenswert?

Hallo, ich habe ein Verständnis Problem.

In meinem Code habe ich eine Endlosschleife. Wenn ein bestimmter Zustand 
eintritt, so soll die Schleife bis zum nächsten Schleifendurchlauf nicht 
mehr betrachtet werden. Sowas mach man ja normal mit continue. Ist das 
bei AVR while(1) in einer main anders?

Ich sende an mein Slave Daten, wenn ein CRC Fehler eintritt, so soll 
halt wieder an den Anfang der while-Schleife. Wie gesagt normal macht 
man dies mit continue, aber wenn ich das verwende, bleibt das programm 
hängen. Ändere ich das in break, so läuft das Programm normal.

Aber das ist ja so dann ja garnicht richtig. Oder verstehe ich da was 
falsch?

So sollte es richtig sein (hängt sich auf):
1
int main(void) {
2
   while(1) {
3
      if(rf12_data()) {
4
         //...
5
         if(cnt == 255) {
6
            continue;
7
         }
8
      }
9
   }
10
}

So läuft das ist aber falsch!:
1
int main(void) {
2
   while(1) {
3
      if(rf12_data()) {
4
         //...
5
         if(cnt == 255) {
6
            break;
7
         }
8
      }
9
   }
10
}

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


Lesenswert?

Meine Glaskugel meinte, dass "cnt" nicht als volatile deklariert ist.

von Guru (Gast)


Lesenswert?

Hmm. Üblicherweise benötigst in einer Endlosschleife in main weder break 
noch continue.

Es ist auch unklar woran Du merkst, das das Programm "hängen bleibt". An 
und für sich gibt es das garnicht. Der uC führt immer irgendwas aus.

Ich sehe in Deinem Code nicht die Bedingung "CRC Fehler" reflektiert. 
Deswegen deute ich das hier mal an.
1
int main(void) {
2
   while(1) {
3
      if(rf12_data()) {
4
         //...
5
         if(!CRC_Fehler) {
6
            mach_was_sinnvolles ();
7
         }
8
      }
9
   }
10
}

Damit wird der Code für den Erfolgsfall eben nur dann ausgeführt, wenn 
alles OK ist, ansonsten einfach zum nächsten Schleifendurchlauf 
übergegangen.

Insgesamt ist Deine Erklärung unklar und es scheint mir, das Du Dir über 
den Ablauf in Kontrollstrukturen nicht klar bist. Wiegesagt ist continue 
und break selten nötig. Ich selbst verwende break nur in switches und 
habe in 30 Jahren noch nie ein continue gebraucht. (Abgesehen von etwas 
komplizierten Fällen in Betriebssystemen). Vor allem möchte ich Dir 
empfehlen das Kapitel hier 
http://openbook.galileocomputing.de/c_von_a_bis_z/008_c_kontrollstrukturen_011.htm#mj23c58e4ac13db1b754398ebbb1825baf
mal durchzulesen.

von Oliver (Gast)


Lesenswert?

ichdu schrieb:
> Ändere ich das in break, so läuft das Programm normal.

In dienem Code sprigst du mit break aus der while(1)-Endlosschleife. 
Danach kommt nichts mehr, also gibt es ein return aus main ins nirwana. 
Das nirwana besteht beim WinAVR aus einer endlosschleife, ergo, der 
Controller "hängt".

Da das aber anscheinend nicht passiert, sind alle weiteren Überlegungen 
müssig, solange du nicht den vollständigen Code zeigst.

Ansonsten hat guru recht - continue braucht man in C noch seltener als 
goto, sprich, nie.

Oliver

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Oliver schrieb:
> Ansonsten hat guru recht - continue braucht man in C noch seltener als
> goto, sprich, nie.

Nö. Continue ist durchaus sehr sinnvoll. Selbst in einer Endlosschleife 
kann es sinnvoll sein.

von Nico S. (nico22)


Lesenswert?

Oliver schrieb:
> Ansonsten hat guru recht - continue braucht man in C noch seltener als
> goto, sprich, nie.

Brr, da würd mir dann aber was fehlen ohne Continue.

von Oliver (Gast)


Lesenswert?

Guru schrieb:
> Hmm. Üblicherweise benötigst in einer Endlosschleife in main weder break
> noch continue.

Rufus Τ. Firefly schrieb:
> Nö. Continue ist durchaus sehr sinnvoll. Selbst in einer Endlosschleife
> kann es sinnvoll sein.

Nico Sch. schrieb:
> Brr, da würd mir dann aber was fehlen ohne Continue.

Nun denn, drei Programmierer, vier Meinungen ;)
Ich bleib bei meiner ;)

Oliver

von U.R. Schmitt (Gast)


Lesenswert?

Vieleicht sollte man verstehen was break und continue überhaupt macht.
ichdu weiß es wohl nicht, oliver wohl auch nicht so genau.

break springt aus einer Schleife raus egal of while for do ... while, 
das heisst die Schleife (bzw. bei mehreren geschachtelten die innerste 
Schleife) wird sofort verlassen. Das ist wie ein goto hinter das 
Schleifenende

continue springt sofort wieder an den Anfang der Schleife, bei einer for 
Schleife führt das dazu, daß die incrementbedingung ausgeführt wird. Das 
ist genau dann sinnvoll, wenn ich den rest des codes in der Schleife 
nicht mehr ausführen will.
Beispiel
do (hole nächste Zeile aus Konfigurationsdatei) {
  if (ist Kommentar) continue;
  verarbeite zeile
  ...
} (while nicht dateiende Konfigurationsdatei)

Oliver und jetzt erzähle nicht da könnte man if else benutzen, wenn du 
mehrere Abbruchbedingungen für die Verarbeitung der aktuellen zeile hast 
ist continue deutlich besser, eleganter, verständlicher.

von U.R. Schmitt (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> liver und jetzt erzähle nicht da könnte man if else benutzen, wenn du
> mehrere Abbruchbedingungen für die Verarbeitung der aktuellen zeile hast
> ist continue deutlich besser, eleganter, verständlicher.
und auch schneller und kleiner weil keine else Zweige ausgewertet werden 
müssen.

von Oliver (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> ichdu weiß es wohl nicht, oliver wohl auch nicht so genau.

Danke, ich weiß das schon sehr genau. Und bin in meinem Leben bisher 
ohne continue ausgekonnen. Bei brak ist das anders, das nutze ich ab und 
an 8ausserhaöb von switch).

U.R. Schmitt schrieb:
> Oliver und jetzt erzähle nicht da könnte man if else benutzen,

Es gibt IMMER mehrere Wege nach Rom, und die wenigsten führen über 
continue.

Oliver

von U.R. Schmitt (Gast)


Lesenswert?

Oliver schrieb:
> Es gibt IMMER mehrere Wege nach Rom, und die wenigsten führen über
> continue.
ROFL!
Eben, weil die meisten Wege nach Rom Umwege sind!
Es gibt in der Regel nur einen schnellsten und einen kürzesten aber 
viele andere, aber du darfst gerne erst nach Frankreich fahren, dort die 
Fähre nach Korsika nehmen und dort dann ne andere zum italienischen 
Festland. dann ist es nicht mehr weit nach Rom, ist bestimmt ne schöne 
Fahrt :-)

Merke: nur wer möglichst viele Wege kennt und bereit ist diese auch zu 
benutzen hat eine größere Chanche den für das Projekt besten Weg zu 
finden.

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


Lesenswert?

U.R. Schmitt schrieb:

> Merke: nur wer möglichst viele Wege kennt und bereit ist diese auch zu
> benutzen hat eine größere Chanche den für das Projekt besten Weg zu
> finden.

Wobei man den besten Weg getrost nach der Ästhetik wählen kann.  Der
compiler wird für mehrere verschieden hingeschriebene Bedingungen oft
genug den gleichen Code ausspucken.

Die Diskussion erinnert mich irgendwie an Donald E. Knuth's Aufsatz:
"Structured Programming with GOTOs".

von U.R. Schmitt (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Wobei man den besten Weg getrost nach der Ästhetik wählen kann.  Der
> compiler wird für mehrere verschieden hingeschriebene Bedingungen oft
> genug den gleichen Code ausspucken.
Das bezweifle ich zumindest für den Fall daß du eine Schleife mit einem 
komplexeren Lnnenleben hast bei dem du sonst ein mehrfaches Abfragen 
nach irgendwelchen Stati machen müsstest, wenn du kein continue benutzen 
würdest.
Wobei man jetzt wieder sagen kann schlecht designt wenn der Code in der 
Schleife so komplex ist ....
Egal, aber wenn man sagt ich brauche kein continue und kein break, dann 
kann man genau so sagen, mir reicht ein do ... while, die while und for 
Schleifen sind vollkommen unnötig, das kann ich alles mit do ... while 
machen.

Jörg Wunsch schrieb:
> Die Diskussion erinnert mich irgendwie an Donald E. Knuth's Aufsatz:
> "Structured Programming with GOTOs".
den kenn ich jetzt leider nicht, aber das Dauerstreitthema goto sind 
"schlecht" / "doch manchmal notwendig" zeigt auch daß Dogmen meistens 
nicht zielführend sind.
ich habe Ablaufcode gesehen wo jeder Aufruf immer ein "if (rc==0) ..." 
hatte, die hätten mit einem goto ERROR besser ausgesehen.
Egal wer nur ein Subset der Befehle nutzen will soll das gerne tun, wie 
gesagt es gibt mehrere Wege...

von Oliver (Gast)


Lesenswert?

U.R. Schmitt schrieb:
> den kenn ich jetzt leider nicht, aber das Dauerstreitthema goto sind
> "schlecht" / "doch manchmal notwendig" zeigt auch daß Dogmen meistens
> nicht zielführend sind.

Die Diskussion ist so alt wie die Programmier-Menschheit, und wird auch 
immer fortbestehen. Der oben genannte Artikel stammt von 1974, und ist 
insofern sicherlich richtig, als daß in den nach diesem Zeitpunkt 
entwickelten höheren Programmiersprachen (also eigentlich fast allen...) 
Strukturen zum "verdeckten" Einsatz von goto enthalten sind, wie 
setjmp/longjmp, try/catch, die doch sehr viel angenehmeres Programmieren 
zulassen, als es mit einer Programmiersprache der "reinen Lehre" wie 
Niclaos' Wirthschen Pascal oder Modula der Fall wäre.

Um aber wieder aufs Thema zurückzukommen:

Das der Code des Threadstartes nicht funktioniert, liegt weder an 
continue noch an break.
Vielleicht meldet der sich ja nochmal mit dem vollständigen Code.

Oliver

von U.R. Schmitt (Gast)


Lesenswert?

Oliver schrieb:
> Das der Code des Threadstartes nicht funktioniert, liegt weder an
> continue noch an break.
> Vielleicht meldet der sich ja nochmal mit dem vollständigen Code.
Da stimme ich dir zu, insofern nichts für ungut :-)
Wenn man wie der TO zur Fehlersuche einfach ein continue durch ein break 
ersetzt, dann möchte ich hier mal Karl Heinz ziteren: "Er braucht 
dringend ein C Buch". -und sollte natürlich auch lesen-

von DirkB (Gast)


Lesenswert?

Wenn ein break die Funktion erfüllt, hat er noch eine Schleife in dem 
//...

von Guru (Gast)


Lesenswert?

Ui. Da habe ich aber was angerichtet!

Es lag nicht in meiner Absicht Dogmen aufzustellen. Ich bin auch der 
Meinung, dass meine Äusserungen:

" Üblicherweise benötigst in einer Endlosschleife in main weder break
noch continue."

und:

"Wiegesagt ist continue und break selten nötig."

nicht als Dogmen zu verstehen sind, die man relativieren muss.

Und mit:

"Ich selbst verwende break nur in switches und habe in 30 Jahren noch 
nie ein continue gebraucht. (Abgesehen von etwas komplizierten Fällen in 
Betriebssystemen)."

habe ich eingeräumt, dass auch ich Gründe kenne, break und continue 
anzuwenden. (Klar. Bei Switch ist das trivial und man kommt nur mit 
Gewalt drum herum).

Wenn ich mir die Beiträge so anschaue so scheint sich jeder der 
Antwortenden zumindest grundsätzlich darüber klar zu sein, dass und wie 
man ein continue vermeiden kann. Irgendwie kommt dann auch immer die 
Ästhetik ins Spiel. Das aber sollte man ernst nehmen, denke ich, und 
hier deswegen keine "Klarstellungen" anfügen. Das man über Geschmack 
streiten kann, ob eine ausformulierte Bedingung mit ausformulierten 
else-if Zweigen nun "schöner" ist, als ein continue, muss letztlich 
jeder selbst entscheiden.

Warum schreibe ich das hier keine Klarstellungen nötig sind?
Nun, weil der TO ganz offensichtlich die Grundlagen nicht beherrscht und 
erstmal überhaupt lernen muss wie while-Schleifen und insbesondere 
unendliche while-Schleifen zu behandeln hat. Insofern waren meine 
relativ formulierte Abweisung von continue und break, meine ich, 
durchaus sinnvoll.
Mit den ganzen Gründen warum und wann continue sinnvoll ist, kann er 
nach meiner Wahrnehmung garnichts anfangen.

Wenn der TO klare Gründe gebracht hätte warum er nun ein continue 
verwenden will, zu erkennen gegeben hätte, das er den anderen Weg kennt 
und nur einen Kommentar dazu gewünscht hätte, was davon zu halten sei, 
das er continue anwendet, wäre das ein anderer Fall gewesen, den ich, 
unter Umständen mit einem Vorbehalt, aber letztlich bejahend beantworten 
hätte müssen.
Wenn er z.B. hätte darlegen können das die Abprüfung von 
Alternativbedingungen notwendig sehr viel Zeit braucht und sein Programm 
zeitkritisch ist, wäre ja gegen continue nichts zu sagen gewesen. 
(Übrigens einer der Fälle z.B. in Betriebssystemen wo ich es auch 
verwenden würde).

Naja. Es fehlt uns jedenfalls eine klare Erklärung des TO zu dem 
Problem, denke ich und einiges an Grundlagenkenntnissen könnte er auch 
noch nachlesen. Bei dem Satz "... so soll die Schleife bis zum nächsten 
Schleifendurchlauf nicht mehr betrachtet werden." hat sich mir doch 
irgendwie was innerlich verwunden. Der uC gibt sich doch keinen 
"Betrachtungen" hin. :-)

von Klaus W. (mfgkw)


Lesenswert?

Die Diskussion geht vollkommen am Kern vorbei.

Schleifen verlässt man prinzipiell mit longjmp(), das ist
portabel und macht mehr Eindruck.

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


Lesenswert?

Klaus Wachtler schrieb:

> Schleifen verlässt man prinzipiell mit longjmp(), das ist
> portabel und macht mehr Eindruck.

Ach was!  Man lässt einen watchdog reset zuschlagen, und wenn man
sich noch irgendwie den vorherigen Zustand merken muss, dann organi-
siert man sich das über eine .noinit-Variable.

Alternativ: man patcht die Einsprungadresse für den nächsten Start
nach dem Reset in die Vektortabelle ... selbstmodifizierender Code,
war zu Z80-Zeiten gang und gäbe. :-))

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.