Guten Tag,
habe diese Schleife in einer älteren C-Firmware von Pic-Microchip
gesehen
und gerätselt:
for(;;)
{
if ((SWITCH_S2) && (!Flags.MotorRunning))
{
while(SWITCH_S2);
RunMotor(); // Run motor if push button is pressed and motor is
// stopped
}
else if ((SWITCH_S2) && (Flags.MotorRunning))
{
while(SWITCH_S2);
StopMotor();// Stop motor if push button is pressed and motor is
// running
}
}
Hat jemand schon eine solch eigenartige for-Schleife gesehen?
Helmut -. schrieb:> Jan S. schrieb:>> Hat jemand schon eine solch eigenartige for-Schleife gesehen?>> Ja. Endlosschleife.
Danke für die Antwort, da hätte man doch gleich while(1) schreiben
können, hat mich etwas verwirrt...
Gruss Jan
Danke auch @ Joachim, Gruss Jan
Jan S. schrieb:> Danke für die Antwort, da hätte man doch gleich while(1) schreiben> können, hat mich etwas verwirrt...
for(;;) kann man als "forever" lesen, das finde ich schöner als
while(1). Da kann man immer noch befürchten, dass es doch mal aufhört ;)
edit: Bonus: for(;;) spart 1 Zeichen!
Bauform B. schrieb:> Jan S. schrieb:>> Danke für die Antwort, da hätte man doch gleich while(1) schreiben>> können, hat mich etwas verwirrt...>> for(;;) kann man als "forever" lesen, das finde ich schöner als> while(1). Da kann man immer noch befürchten, dass es doch mal aufhört ;)
edit: Bonus: for(;;) spart 1 Zeichen!
☺️☺️ Gruss Jan
Jan S. schrieb:> da hätte man doch gleich while(1) schreiben können
Bei "for (;;)" ist offensichtlich, dass der Autor das so wollte, das
entsteht nicht mal irgendwo aus Versehen.
"while(1)" könnte beispielsweise aus einer Makroersetzung "while
(IS_SOMETHING_GOING_ON())" kommen, deren Inhalt unbeabsichtigt zu "1"
wurde, daher lässt man sowas den Compiler lieber warnen.
Folglich gibt es style guides, die "for (;;)" explizit für eine
Endlosschleife vorschreiben.
Hallo,
Jan S. schrieb:> ...da hätte man doch gleich while(1) schreiben> können...
Im Buch "Code complete" von Steve McConnell wird für C empfohlen eine
Endlosschleife mit einem Makro einzuleiten:
@Jörg
@Roland
@Wilhelm
Danke für die Antworten.
Ach, als wäre es nicht schon kompliziert genug, sich durch all die
Deklarationen und Makros von Microchip zu kämpfen...
😓 Gruss Jan
Jörg W. schrieb:> "while(1)" könnte beispielsweise aus einer Makroersetzung "while> (IS_SOMETHING_GOING_ON())" kommen, deren Inhalt unbeabsichtigt zu "1"> wurde, daher lässt man sowas den Compiler lieber warnen.
Was soll der Compiler denn warnen, wenn das Macro zu 1 oder true ersetzt
wird?
Wilhelm M. schrieb:> Was soll der Compiler denn warnen, wenn das Macro zu 1 oder true ersetzt> wird?
"condition is always true" oder sowas.
Zumindest irgendwelche lint müssen sowas moniert haben.
Bauform B. schrieb:> Jan S. schrieb:>> Danke für die Antwort, da hätte man doch gleich while(1) schreiben>> können, hat mich etwas verwirrt...>> for(;;) kann man als "forever" lesen, das finde ich schöner als
Lächerlich.
Hinterlass lieber einen comment, der auch dem dümmsten Source-Code Leser
klar macht, was hier gemeint ist.
Und wer sich nicht scheut, das "verpönte" goto in C einzusetzen könnte
es auch schreiben wie es realisiert wird:
forever: goto forever;
https://www.javatpoint.com/infinite-loop-in-chttps://stackoverflow.com/questions/20186809/endless-loop-in-c-c
for(;;) ist vorgesehen als Standard-Endlosschleife.
While erfordert einen Ausdruck, während bei "for" das zweite Argument
explizit optional ist (die andern beiden auch, da braucht es aber keine
Sonderbehandlung):
"An omitted expression-2 is replaced by a nonzero constant"
Frank M. schrieb:> Auf den ersten Blick ein schöner Hack, allerdings wird
1
while("never")
2
{
3
}
> leider nicht den gewünschten Effekt haben.
War auch nicht die Intention. Jedes Stringarray steht an einer Adresse
!= 0. Der Inhalt des Strings ist also immer egal.
Wilhelm M. schrieb:> Roland F. schrieb:>> Im Buch "Code complete" von Steve McConnell wird für C empfohlen eine>> Endlosschleife mit einem Makro einzuleiten:>>>>
Bruno V. schrieb:> for(;;) ist vorgesehen als Standard-Endlosschleife.> While erfordert einen Ausdruck, während bei "for" das zweite Argument> explizit optional ist
Ja, das ist für mich auch der Grund, warum ich for(;;) bevorzuge. Es
gibt keine Bedingung für die Schleife, und bei for kann ich das auch
direkt so ausdrücken. Bei while muss ich dagegen eine Pseudo-Bedingung
hinschreiben.
Rolf M. schrieb:> Bruno V. schrieb:>> for(;;) ist vorgesehen als Standard-Endlosschleife.>> While erfordert einen Ausdruck, während bei "for" das zweite Argument>> explizit optional ist>> Ja, das ist für mich auch der Grund, warum ich for(;;) bevorzuge. Es> gibt keine Bedingung für die Schleife, und bei for kann ich das auch> direkt so ausdrücken.
Das ist doch an den Haaren herbei geholt!
> Bei while muss ich dagegen eine Pseudo-Bedingung> hinschreiben.
Wieso Pseudo? Die Bedingung statt ganz klar als Literal "true" dort. Nix
Pseudo.
Bei for steht nichts, und man muss, falls man das Idiom nicht kennt,
nachdenken. Bei while steht es explizit da. Und explizit ist immer
besser als implizit.
Peter D. schrieb:> int main(void)> {> do> {> // ...> }> while("Forever");> }
"while forever" ("während für immer") sagt kein Mensch, nicht einmal ein
Engländer aus gehobenen Kreisen. Deswegen etwas besser:
1
for(;"ever";){
2
...
3
}
Aber wie die meisten Vorposter würde ich des "ever" einfach weglassen :)
Wilhelm M. schrieb:>> Ja, das ist für mich auch der Grund, warum ich for(;;) bevorzuge. Es>> gibt keine Bedingung für die Schleife, und bei for kann ich das auch>> direkt so ausdrücken.>> Das ist doch an den Haaren herbei geholt!
Warum? Ich will eine unbedingte Schleife, habe also keine Bedingung. Bei
for kann ich diese weglassen und bekomme dann genau das, was ich will.
Was ist daran "an den Haaren herbei geholt"? Das passt doch nun wirklich
wie die sprichwörtliche Faust aufs Auge.
Wilhelm M. schrieb:>> Bei while muss ich dagegen eine Pseudo-Bedingung>> hinschreiben.>> Wieso Pseudo?
Weil eine 1 von nichts abhängt. Damit ist es keine echte Bedingung. In
Assembler würde ich eine Endlosschleife auch nicht so schreiben, dass
ich in jedem Durchlauf prüfe, ob 1 immer noch ungleich 0 ist und dann
einen bedingten Sprung machen. In C(++) muss ich das auch nicht, dank
for(;;).
> Bei for steht nichts, und man muss, falls man das Idiom nicht kennt,> nachdenken.
Ja, wenn man ein Sprachelement nicht kennt, muss man "nachdenken", bzw.
es eben lernen.
> Bei while steht es explizit da.
Was? Da steht ein "true". Also eine Schleife, die so lange läuft, wie
"wahr" wahr ist. Das ist nicht explizit in der Aussage, dass ich eine
unbedingte Schleife haben will. Es ist unnötig umständlich.
Ich versuche eigentlich immer, möglichst das hinzuschreiben, was ich
meine. So schreibe ich z.B. wenn ich einen Integer mit 2 multiplizieren
will, * 2 hin und nicht << 1. Und wenn ich eine Schleife ohne Bedingung
will, schreibe ich eben eine ohne Bedingung hin und nicht eine mit einer
"Bedingung", die auf triviale Weise immer true ist.
> Und explizit ist immer besser als implizit.
Richtig.
Gegen while(1) spricht, dass manche statischen Analyse-Tools meckern,
wenn man sie nicht entsprechend konfiguriert. Üblicher ist
wahrscheinlich while(1), weil es "lesbarer" ist. Auch wenn for(;;) wohl
eher die bestimmungsgemäße Variante für eine Endlosschleife ist.
Aber um sich ein FOREVER-Macro zu machen muss man ja völlig besoffen
sein...
Rolf M. schrieb:> Weil eine 1 von nichts abhängt. Damit ist es keine echte Bedingung.
Natürlich gibt es Bedingungen, die immer wahr sind.
> In> Assembler würde ich eine Endlosschleife auch nicht so schreiben,
Dann mach das doch auch in C.
Rolf M. schrieb:> Was? Da steht ein "true".
Sehr richtig.
> Also eine Schleife, die so lange läuft, wie> "wahr" wahr ist. Das ist nicht explizit in der Aussage, dass ich eine> unbedingte Schleife haben will.
Sehr explizit.
Denn wo ist es denn explizit bei /for(;;)/, dass es eine endlos Schleife
sein soll??? Das muss man sich mühsam, aus dem C-Standard raussuchen.
> Es ist unnötig umständlich.> Ich versuche eigentlich immer, möglichst das hinzuschreiben, was ich> meine. So schreibe ich z.B. wenn ich einen Integer mit 2 multiplizieren> will, * 2 hin und nicht << 1. Und wenn ich eine Schleife ohne Bedingung> will, schreibe ich eben eine ohne Bedingung hin und nicht eine mit einer> "Bedingung", die auf triviale Weise immer true ist.
Und dieser Satz stört Dich bei /for(;;)/ nicht?
"An omitted expression-2 is replaced by a nonzero constant"
Der Bedingungsausdruck ist nämlich auch bei for konstant, und damit
keine Bedingung nach Deiner Definition.
Wilhelm M. schrieb:>> In>> Assembler würde ich eine Endlosschleife auch nicht so schreiben,>> Dann mach das doch auch in C.
Hä? Das mache ich doch. Das war doch genau der Punkt. Dazu brauche ich
aber for, weil das mit while nicht geht.
> Rolf M. schrieb:>> Was? Da steht ein "true".>> Sehr richtig.>>> Also eine Schleife, die so lange läuft, wie>> "wahr" wahr ist. Das ist nicht explizit in der Aussage, dass ich eine>> unbedingte Schleife haben will.>> Sehr explizit.
Also ich finde "Schleife: …" eher explizit für eine Endlosschleife als
"Schleife, solange wahr wahr ist: …".
> Denn wo ist es denn explizit bei /for(;;)/, dass es eine endlos Schleife> sein soll???
Es ist sehr explizit darin, dass es eine Schleife ist, die keine
Bedingung hat, also eine Endlosschleife, denn es steht ja keine
Bedingung dran, von der die weitere Ausführung abhängen könnte.
> Das muss man sich mühsam, aus dem C-Standard raussuchen.
Und da sprichst du von an den Haaren herbeigezogenen Dingen. Ich habe
schon ganz zu Anfang gelernt, dass bei for() alle drei Teile optional
sind. Das sollte eigentlich in jedem Anfängerbuch stehen.
> Und dieser Satz stört Dich bei /for(;;)/ nicht?>> "An omitted expression-2 is replaced by a nonzero constant"
Nö, warum? Wie der Compiler das umsetzt, ist mir eigentlich egal.
Rolf M. schrieb:> Es ist sehr explizit darin...
Ersetze explizit mit kryptisch, dann passt es.
Oder in deiner Sprache: 's/explizit/kryptisch/'
Rolf M. schrieb:> So schreibe ich z.B. wenn ich einen Integer mit 2 multiplizieren> will, * 2 hin und nicht << 1.
Sehr löblich. Warum Du dann bei Schleifen Konstrukte bevorzugst, die
aussehen als wenn eine Katze über die Tastatur gelaufen ist, weißt wohl
nur du.
Joe schrieb:> Ein Blick in das C-Standardwerk K&R 'Programmieren in C' zeigt> diese Form der Endlosschleife als die von den Autoren bevorzugte.> for(;;)
Damit habe ich vor 35 Jahren C gelernt, und selbst da war das Buch schon
10 Jahre alt.
Wenn man das als Dogma nehmen möchte, macht man sicher nix falsch.
Ich bin trotzdem froh, dass sich die Welt seither etwas weitergedreht
hat.
Wilhelm M. schrieb:> Das muss man sich mühsam, aus dem C-Standard raussuchen.Klaus schrieb:> Ersetze explizit mit kryptisch, dann passt es.
Ich muss sagen, dass ich doch erstaunt bin, dass so erfahrene
Programmierer derart große Probleme mit so einem simplen Konzept haben.
Rolf M. schrieb:> Wilhelm M. schrieb:>> Das muss man sich mühsam, aus dem C-Standard raussuchen.>> Ich muss sagen, dass ich doch erstaunt bin, dass so erfahrene> Programmierer derart große Probleme mit so einem simplen Konzept haben.
Du weißt schon noch, wer die Frage gestellt hat, oder?
Klaus schrieb:> Joe schrieb:>> Ein Blick in das C-Standardwerk K&R 'Programmieren in C' zeigt>> diese Form der Endlosschleife als die von den Autoren bevorzugte.>> for(;;)>> Damit habe ich vor 35 Jahren C gelernt, und selbst da war das Buch schon> 10 Jahre alt.
In der 10 Jahre jüngeren 2. Auflage steht das immer noch so :)
> Wenn man das als Dogma nehmen möchte, macht man sicher nix falsch.> Ich bin trotzdem froh, dass sich die Welt seither etwas weitergedreht> hat.
Natürlich hat sich seither vieles verändert, aber wohl kaum die
Argumentation für oder gegen for bzw. while zur Bildung von
Endlosschleifen.
Chuck Norris würde übrigens while nehmen, aber nicht etwa while(1),
sondern
1
while(UINTMAX_MAX){
2
...
3
}
Das ergibt nämlich nicht nur unendlich viele, sondern UINTMAX_MAX mal
unendlich viele Schleifendurchläufe, so dass er mehr Spaß beim Abzählen
derselben hat. Wenn er damit durch ist, ändert er UINTMAX_MAX in
INFINITY ;-)
> Natürlich hat sich seither vieles verändert, aber wohl kaum die> Argumentation für oder gegen for bzw. while zur Bildung von> Endlosschleifen .
Doch, da hat sich gerade im Embedded einiges getan, sogar bis zur
Abschaffung der Schleife als Realisierung eines (Endlosen) Dauerlauf.
Und zwar durch Implementierung verschiedener Sleep-Modus und diverse
Möglichkeiten des Aufwachens.
Aber das nur für die (Embedded-)Entwickler, die gewillt sind, über den
Tellerand einer Akademischen Instrumentalisierung einer
Programmiersprache hinaus zu schauen ;-)
BTW: weitaus wichtiger für einen Programmierer als der
(absichtliche/unabsichtliche) Start in eine Endlos-Schleife sind die
Möglichkeiten eine solche kontrolliert zu verlassen, gerade weil eben
das Ende in einer Endlos-Schleife nicht vorgesehen ist ;-)
Rudolph R. schrieb:> Ansonsten hat aber Jörg da ganz weit oben das schon gut begründet,
Hört sich fast so an, als wärt ihr katholisch: nur weil das vor Äonen
schon mal im K&R stand, bedeutet das (für mich) nicht, dass man das so
machen sollte. Ich denke da lieber selbst ;-)
> hier> noch ein Link dazu als Beispiel für Coding Guidelines:> https://barrgroup.com/embedded-systems/books/embedded-c-coding-standard/statement-rules/for-while-loops
Dort steht auch gar keine Begründung, sondern nur eine Kodier-Anweisung.
Das Beispiel ist ja völlig irrelevant (s.a. Fußnote dort), weil man eben
heute auch C nicht while(1) sondern while(true) schreibt (schreiben
sollte).
Klaus schrieb:> Joe schrieb:>> Ein Blick in das C-Standardwerk K&R 'Programmieren in C' zeigt>> diese Form der Endlosschleife als die von den Autoren bevorzugte.>> for(;;)>> Damit habe ich vor 35 Jahren C gelernt, und selbst da war das Buch schon> 10 Jahre alt.> Wenn man das als Dogma nehmen möchte, macht man sicher nix falsch.> Ich bin trotzdem froh, dass sich die Welt seither etwas weitergedreht> hat.
Mir ging es nur um die Frage des TO ob schon mal jemand for(;;) gesehen
hat.
Ich selber schreibe auch lieber while(1). Letztlich ist es einfach
Geschmackssache. Jeder wie er's mag.
DSGV-Violator schrieb:> Doch, da hat sich gerade im Embedded einiges getan, sogar bis zur> Abschaffung der Schleife als Realisierung eines (Endlosen) Dauerlauf.> Und zwar durch Implementierung verschiedener Sleep-Modus und diverse> Möglichkeiten des Aufwachens.
So, wie ich das bei den Pic-MC verstanden habe, muss zwingend eine
Endlosschlaufe vorhanden sein od. bei ASM loop: goto od. branch to loop.
Sonst würde der Programmzähler ins Leere laufen oder?
DSGV-Violator schrieb:> Doch, da hat sich gerade im Embedded einiges getan, sogar bis zur> Abschaffung der Schleife als Realisierung eines (Endlosen) Dauerlauf.> Und zwar durch Implementierung verschiedener Sleep-Modus und diverse> Möglichkeiten des Aufwachens.
Was hat das eine jetzt mit dem anderen zu tun?
Ohne Software-Schleife kommt man nur aus wenn das Programm immer wieder
durch den Reset-Vector läuft, ansonsten schickt man den Controller am
Ende der Schleife in den gewünschten Sleep-Mode und ist durch das
Wakeup-Event am Anfang der Schleife.
In einen PowerDown Mode zu gehen ist eher sowas wie das Programm zu
beenden um irgendwann später mal neu zu starten, aber doch nicht was für
den regulären Umlauf, dafür dauert das Aufwachen viel zu lange.
Wilhelm M. schrieb:> Grundsätzlich sind in C/C++ Endlos-Schleifen, die keine Seiteneffekte> enthalten, UB
Sie können entfernt werden, ja. Aber, dass sie UB sind, würde ich mal
stark bezweifeln. Wo steht das?
MaWin O. schrieb:> Wilhelm M. schrieb:>> Grundsätzlich sind in C/C++ Endlos-Schleifen, die keine Seiteneffekte>> enthalten, UB>> Sie können entfernt werden, ja. Aber, dass sie UB sind, würde ich mal> stark bezweifeln. Wo steht das?
1
In a valid C++ program, every thread eventually does one of the following:
2
3
terminate;
4
makes a call to an I/O library function;
5
performs an access through a volatile glvalue;
6
performs an atomic operation or a synchronization operation.
7
This allows the compilers to remove all loops that have no observable behavior, without having to prove that they would eventually terminate because it can assume that no thread of execution can execute forever without performing any of these observable behaviors.
Das bedeutet, dass eine Endlos-Schleife ohne Seiteneffekt kein valides
C++ Programm ist. Und das bedeutet, dass es UB ist.
Wilhelm M. schrieb:>> hier>> noch ein Link dazu als Beispiel für Coding Guidelines:>>> https://barrgroup.com/embedded-systems/books/embedded-c-coding-standard/statement-rules/for-while-loops>> Dort steht auch gar keine Begründung, sondern nur eine Kodier-Anweisung.>> Das Beispiel ist ja völlig irrelevant (s.a. Fußnote dort), weil man eben> heute auch C nicht while(1) sondern while(true) schreibt (schreiben> sollte).
Die Fußnote hast Du also gefunden, da steht auch eine Begründung.
Mit while(true) bin ich nicht einverstanden, aber der Grund für meinen
Post war auch nicht das for(;;) zu verteidigen oder was anderes
abzulehnen, sondern eine konkrete Coding Guideline zu zitieren in
welcher das genau so gefordert ist.
"8.4.c. Infinite loops shall be implemented via controlling expression
for (;;)."
Wenn man sich an eine Coding Guideline halten muss, dann gibt es da gar
keine Diskussion mehr, die Fußnote macht es nur leichter von der
persönlichen Vorliebe abzuweichen um am Ende Regel-konformen Code
abzuliefern.
Hast Du schon mal einen Pull-Request in einem größeren Projekt gemacht?
Wilhelm M. schrieb:> In a valid C++ program, every thread eventually does one of the> following:
Aus welcher Version ist das? Im letzten Draft, den ich finden konnte,
fängt dieser Absatz mit "The implementation may assume that any thread
will eventually do one of the following:" an.
Wilhelm M. schrieb:> In a valid C++ program, every thread eventually does one of the> following:
Und was startet die Threads?
Doch nicht etwa der Scheduler der in einer Endlos-Schleife läuft?
Rudolph R. schrieb:> Doch nicht etwa der Scheduler der in einer Endlos-Schleife läuft?
Erstens ist durch den Standard nicht vorgegeben, wie der Scheduler
implementiert sein muss, zweitens wüsste ich nicht, wie er ohne "side
effects" in der Lage sein soll, Threads zu starten.
Rolf M. schrieb:> Rudolph R. schrieb:>> Doch nicht etwa der Scheduler der in einer Endlos-Schleife läuft?>> Erstens ist durch den Standard nicht vorgegeben, wie der Scheduler> implementiert sein muss, zweitens wüsste ich nicht, wie er ohne "side> effects" in der Lage sein soll, Threads zu starten.
Das ist auch nicht relevant dafür das jedes Embedded Programm irgendwo
eine Endlos-Schleife haben muss und der Versuch den Goalpost auf Threads
zu verschieben eher albern war in dem Zusammenhang.
Rudolph R. schrieb:> Das ist auch nicht relevant dafür das jedes Embedded Programm irgendwo> eine Endlos-Schleife haben muss
Lies dir den Standard-Text halt einfach mal genau durch. Es ist sehr
genau definiert (kein UB) wann eine Endlosschleife wegoptimiert werden
kann. Eine Embedded-Endlossschleife fällt dort in der Regel nicht
darunter. Es sei denn, sie macht nichts nach außen hin sichtbares.
MaWin O. schrieb:> Lies dir den Standard-Text halt einfach mal genau durch.
"In a valid C++ program, every *thread*"
"The implementation may assume that any *thread*"
Alles nach thread ist doch in dem Kontext hier bedeutungslos.
Rudolph R. schrieb:> Alles nach thread ist doch in dem Kontext hier bedeutungslos.
Nein, denn wenn es keinen Thread gibt, gibt's auch kein Programm, denn
auch main() und alles, was von da aufgerufen wird, ist Teil eines
Threads. Der Unterschied zu anderen Threads ist lediglich, dass er halt
gleich vom System angelegt wird und nicht manuell erzeugt werden
muss/kann.
> Was hat das eine jetzt mit dem anderen zu tun?
beides ist eine Implementierung von reaktionsbereiten Dauerlauf.
> Ohne Software-Schleife kommt man nur aus wenn das Programm immer wieder> durch den Reset-Vector läuft,
Och, zum Verlassen eine Endlosrn Schleifen gibt es noch weitere
Möglichkeiten wie break oder goto.
> ansonsten schickt man den Controller am> Ende der Schleife in den gewünschten Sleep-Mode und ist durch das> Wakeup-Event am Anfang der Schleife.
Nö, da ist man am Startvector des jeweiligen WakeUps, der nicht gleich
mit dem Start der Schleife sein muß. IRQ ist da beliebt, beim MC68k gabs
da die Unterscheidung in Cold und Cool Capture.
> In einen PowerDown Mode zu gehen ist eher sowas wie das Programm zu> beenden um irgendwann später mal neu zu starten, aber doch nicht was für> den regulären Umlauf, dafür dauert das Aufwachen viel zu lange.
Nö, nicht im Embedded insbesonders beim Batteriebetrieb. Da ist Sleep
der an häufigsten angenommen Betriebszustand. Sleep- und PowerDown ist
nicht unbedingt dasselbe.
DSGV-Violator schrieb:>> Ohne Software-Schleife kommt man nur aus wenn das Programm immer wieder>> durch den Reset-Vector läuft,>> Och, zum Verlassen eine Endlosrn Schleifen gibt es noch weitere> Möglichkeiten wie break oder goto.
Kann es sein, dass du dich verlesen hast?
Eines kann man jedenfalls dem Thread entnehmmen:
Jede Programmiersprache eignet sich bestens zur geistigen Onanie und zur
ausführlichen Diskussion über die resultierenden Ergüsse.
Grad mal im Parser in der Backus.Nauer-Form nachgeschaut.
1
<iteration-statement> ::= while ( <expression> ) <statement>
2
| do <statement> while ( <expression> ) ;
3
| for ( {<expression>}? ; {<expression>}? ; {<expression>}? ) <statement>
Da stellt sich jetzt die Frage ob einauf seinen Start rückgeppolter
Block eine "Iteration" ist und ob es einen Unterschied zwische Iteration
(lat. 'itero') und Repitation (lat.: 'repeto') geben muß.
Rudolph R. schrieb:> Wenn man sich an eine Coding Guideline halten muss, dann gibt es da gar> keine Diskussion mehr,
Leider vollkommen am Thema hier vorbei: es geht um keine
Kodier-Richtinie.
DSGV-Violator schrieb:> Da stellt sich jetzt die Frage ob einauf seinen Start rückgeppolter> Block eine "Iteration" ist und ob es einen Unterschied zwische Iteration> (lat. 'itero') und Repitation (lat.: 'repeto') geben muß.
Warum sollte die Frage, welches lateinische Wort das am besten passende
wäre, für die Diskussion relevant sein?
Roland F. schrieb:> Hallo,>> Leider vollkommen am Thema hier vorbei: es geht um keine>> Kodier-Richtinie.>> Genau, und es geht auch nicht um UB in C++.
Schau nochmal auf welchen Beitrag ich das geschrieben hatte. Und wenn du
magst streiche das ++.
Rolf M. schrieb:> DSGV-Violator schrieb:>> Da stellt sich jetzt die Frage ob einauf seinen Start rückgeppolter>> Block eine "Iteration" ist und ob es einen Unterschied zwische Iteration>> (lat. 'itero') und Repitation (lat.: 'repeto') geben muß.>> Warum sollte die Frage, welches lateinische Wort das am besten passende> wäre, für die Diskussion relevant sein?
Weil eben eine Iteration wie aus dem Mathematischen Prinzip der
vollständigen Induktion bekannt keine Wiederholung (im Kreis laufen)
ist. Kennzeichnen für eine Iteration (fortschreitend, i.e. Spirale) ist
eben der sich ändernde Index, der eben bei der Notation als leere loop
fehlt, obwohl essential für eine Iteration.
https://de.wikipedia.org/wiki/Spirale#Ebene_Spiralenhttps://de.wikipedia.org/wiki/Kreis
Iteration und Repetition sind verwandt, aber linguistisch nicht gleich:
mit Repetition ist die Wiederholung einer Sache in immer derselben Art
gemeint. Mit Iteration ist eine Wiederholung gemeint, die sich von den
vorherigen unterscheidet.
In Bezug auf eine Zustandsmaschine wie ein valides C-Programm (auf einem
µC) dürfte es demnach keine wirkliche Repetition gegen. Denn: ein
C-Programm ohne Seiteneffekte ist kein valides C-Programm, und damit
ändert sich also der Gesamtzustand des Programms (SW und HW). Also haben
wir eine Iteration. Viele Linguisten würden allerdings wohl auch den
Begriff der Repetition als Oberbegriff bezeichnen, und die Iteration ist
dann eben eine spezielle Ausprägung dessen.
Oder man benutzt statt der Fremdwörter "Iteration" und "Repetition"
einfach das deutsche Wort "Schleife" und geht damit automatisch allen
Spitzfindigkeiten aus dem Weg :)
Yalu X. schrieb:> Oder man benutzt statt der Fremdwörter "Iteration" und "Repetition"> einfach das deutsche Wort "Schleife"
Schleife macht man am Schuh.
> und geht damit automatisch allen> Spitzfindigkeiten aus dem Weg :)
Was Du meinst, ist einfache eine Wiederholung.
DSGV-Violator schrieb:> Da stellt sich jetzt die Frage ob einauf seinen Start rückgeppolter> Block eine "Iteration" ist und ob es einen Unterschied zwische Iteration> (lat. 'itero') und Repitation (lat.: 'repeto') geben muß.
Man sollte also vorsichtshalber weder while(true) noch for(;;)
verwenden, sondern sich auf das linguistisch völlig unverdächtige goto
verlegen. ;-)
(prx) A. K. schrieb:> sondern sich auf das linguistisch völlig unverdächtige goto> verlegen. ;-)
Wie soll denn eine CPU oder ein Compiler ganz ohne Füße irgendwo
hingehen?
Hallo,
Yalu X. schrieb:> Oder man benutzt statt der Fremdwörter "Iteration" und "Repetition"> einfach das deutsche Wort "Schleife" und geht damit automatisch allen> Spitzfindigkeiten aus dem Weg :)
Zu einfach, das würde ja jeder verstehen.
rhf
Hallo,
2 Zitate:
Bjarne Stroustrup
"Die etwas eigenartige anmutende Notation for(;;) codiert eine
Endloschleife. Eine alternative Anweisung hierfür ist while(true)."
Ulrich Breymann
Äquivalenz von for und while.
"Eine for Schleife entspricht direkt einer while-Schleife, sie ist im
Grunde nur eine Umformulierung, solange nicht continue vorkommt."
Das heißt, ob nun for(;;) oder while(1) ist vollkommen egal. Die Wirkung
was es tut ist exakt gleich. Von daher schreibt was euch gefällt. Sonst
wird das ein Endlos-Thread. ;-)
Veit D. schrieb:> Das heißt, ob nun for(;;) oder while(1) ist vollkommen egal.
Im originalen C&R hat "for(;;)" gegen "while(1)" deshalb gewonnen,
weil's ein Zeichen weniger zu tippsen ist :-)
Veit D. schrieb:> Das heißt, ob nun for(;;) oder while(1) ist vollkommen egal.
Das wussten wir (ok, vllt außer dem TO) doch schon alle vorher.
> Die Wirkung> was es tut ist exakt gleich.
Auch das ist nichts Neues, und darum ging es ja mal wieder überhaupt
nicht: es ging doch darum, was "besser lesbar" sei. Und das ist nunmal
subjektiv.
> Von daher schreibt was euch gefällt.
Natürlich, was denn sonst?
Johann L. schrieb:> Im originalen C&R hat "for(;;)" gegen "while(1)" deshalb gewonnen,> weil's ein Zeichen weniger zu tippsen ist :-)
Dann sieht's für while(true) ja ganz schlecht aus. 😉
Johann L. schrieb:> Veit D. schrieb:>> Das heißt, ob nun for(;;) oder while(1) ist vollkommen egal.>> Im originalen C&R hat "for(;;)" gegen "while(1)" deshalb gewonnen,> weil's ein Zeichen weniger zu tippsen ist :-)
Wann hat denn der gute Brian seinen Namen gewechselt?
Eine interessante Frage kam mir an diesem sonntaglichen herumlungern:
Gibt es eine Möglichkeit das Abbrechen einer Endlosschleife (Egal ob als
do/while/for...) mittels "break" zu verhindern?
Ich hatte mal den Fall dass ein überzeugter C-Preprozessor Jünger ein
"break" gut in den Innereien versteckt hatte... (Dauerte einige Zeit den
Fehler zu identifizieren. Danach wurde der Hacker mit reichlich
Katzenscheiße beworfen...)
Wilhelm hatte oben doch ein C++ Vorschlag mit
Klaus H. schrieb:> Wilhelm hatte oben doch ein C++ Vorschlag mit> repeat<forever>([]{> // ...> });>> Gibt es da ein Konstrukt?
Was meinst Du?
Wie das obige repeat- realisiert werden soll? Ist eigentlich Grundkurs
generische Programmierung.
Oder, ob es durch ein break abgebrochen werden kann? Nein, kann es
nicht.
Wilhelm M. schrieb:> Wie das obige repeat- realisiert werden soll? Ist eigentlich Grundkurs> generische Programmierung.
Bisher hab ich nur endliche Schleifen erzeugt. Wie würde man eine
endlose Schleife erzeugen?
Klaus H. schrieb:> Bisher hab ich nur endliche Schleifen erzeugt. Wie würde man eine> endlose Schleife erzeugen?
Kannst Du die beiden wesentlichen Elemente benennen, die ich in dem
Beispiel benutzt habe? Dann weißt Du auch die Lösung ;-)
Yalu X. schrieb:> Oder man benutzt statt der Fremdwörter "Iteration" und "Repetition"> einfach das deutsche Wort "Schleife" und geht damit automatisch allen> Spitzfindigkeiten aus dem Weg :)
Wer die Spitzfindigkeit nicht ehrt, ist die C-Syntax nicht wert ;-)
Siehe auch:
https://en.wikipedia.org/wiki/International_Obfuscated_C_Code_Contest#Flight_simulator
Abgesehen davon das mit einem nur grob ausgebildeten Gefühl für die
Schriftsprache aus dem schmückenden "Schleife knüpfen/binden" schnell
ein strangulierendes "Schlinge knüpfen/binden" wird.
Schlinge, Schleife ... alles nur Gestricke ;-)
Wilhelm M. schrieb:> Kannst Du die beiden wesentlichen Elemente benennen, die ich in dem> Beispiel benutzt habe? Dann weißt Du auch die Lösung ;-)
Was meinst Du? Du nutzt ein Template und als Parameter eine Lambda
Expression.
Klaus H. schrieb:> Was meinst Du? Du nutzt ein Template und als Parameter eine Lambda> Expression.
Perfekt.
Damit sollte doch die Realisierung klar sein, oder?
Wilhelm M. schrieb:> Perfekt.> Damit sollte doch die Realisierung klar sein, oder?
Tatsächlich stehe ich auf dem Schlauch. Es muss ja zur Compilezeit
aufgelöst werden können. Das geht IMHO nur wenn ich im Template eine
Endlosschleife ala while(1) {...} nutze, oder? Dann hab ich aber ja
ursprüngliche Konstrukt.
Wie würdest Du es lösen?
Klaus H. schrieb:> Gibt es da ein Konstrukt?
Damit wird break zu continue, und es ist für jeden was dabei:
for(;;) while(true) {
...
}
Für C-Ästheten:
#define loop for(;;)
#define forever while(true)
loop forever {
...
}
Klaus H. schrieb:> Tatsächlich stehe ich auf dem Schlauch. Es muss ja zur Compilezeit> aufgelöst werden können. Das geht IMHO nur wenn ich im Template eine> Endlosschleife ala while(1) {...} nutze, oder?
Genau.
Da aber das "break" im Closure stehen würde, wäre es syntaktisch falsch.
> Dann hab ich aber ja> ursprüngliche Konstrukt.
Naja, in dem Funktionstemplate kannst Du dann alles benutzen, was wir
hier diskutiert haben, auch Dein goto ;-)
Klaus H. schrieb:> Wilhelm M. schrieb:>> Damit sollte doch die Realisierung klar sein, oder?>> OK, du meinst vermutlich ein Konstrukt ala>>
1
>template<typenameT>voidforever(Tlambda){
2
>while(true){
3
>lambda();
4
>}
5
>}
6
>
7
>intmain(){
8
>forever([](){
9
>//...
10
>});
11
>return0;
12
>}
13
>
Ich hatte verschiedene Spezialisierungen in meinem Beispiel benutzt,
damit kann man es noch etwas ausgestalten.
Oder einfach:
1
voidforever(autof){
2
while(true){
3
f();
4
}
5
}
Was Du übergeben bekommst, ist keine Lamba-Expression, sondern das
Ergebnis(!) einer solchen, also ein Closure. Daher ist der Parametername
"lambda" nicht gut. Es ist einfach ein Funktionsobjekt "f", das kann
auch ein Funktor odgl. sein.
Wilhelm M. schrieb:> Daher ist der Parametername> "lambda" nicht gut. Es ist einfach ein Funktionsobjekt "f", das kann> auch ein Funktor odgl. sein.
Stimmt, die allgemeine Form ist besser.
Danke, dann hatte ich es korrekt verstanden.
Das Konstrukt könnte durchaus mal interessant sein,
wenn viel über Lambda Expressions abgehandelt wird.
Klaus H. schrieb:> Das Konstrukt könnte durchaus mal interessant sein,> wenn viel über Lambda Expressions abgehandelt wird.
Wer generische Lambda-Expressions verstanden hat, der hat C++ verstanden
;-)
Wilhelm M. schrieb:> Wer generische Lambda-Expressions verstanden hat, der hat C++ verstanden> ;-)
Damit hast du keine Probleme, aber dass bei for die Bedingung optional
ist, findest du zu kompliziert?
Rolf M. schrieb:> Wilhelm M. schrieb:>> Wer generische Lambda-Expressions verstanden hat, der hat C++ verstanden>> ;-)>> Damit hast du keine Probleme, aber dass bei for die Bedingung optional> ist, findest du zu kompliziert?
Hallo???
Es ging doch um den TO! Du verdrehst hier immer alles ...
Mein Kommentar bezog sich ganz offensichtlich auf Klaus H., der das
verstanden hat.
Wilhelm M. schrieb:> Rolf M. schrieb:>> Wilhelm M. schrieb:>>> Wer generische Lambda-Expressions verstanden hat, der hat C++ verstanden>>> ;-)>>>> Damit hast du keine Probleme, aber dass bei for die Bedingung optional>> ist, findest du zu kompliziert?>> Hallo???> Es ging doch um den TO!
Und nachdem der TO schon mit for(;;) Probleme hatte, glaubst du, dass er
dieses hier
Wilhelm M. schrieb:> repeat<forever>([]{> // ...> });
auf Anhieb versteht und sogar in der Lage ist, die dafür benötigte
Template-Funktion selber zu schreiben? :-)
Yalu X. schrieb:> Wilhelm M. schrieb:>> Rolf M. schrieb:>>> Wilhelm M. schrieb:>>>> Wer generische Lambda-Expressions verstanden hat, der hat C++ verstanden>>>> ;-)>>>>>> Damit hast du keine Probleme, aber dass bei for die Bedingung optional>>> ist, findest du zu kompliziert?>>>> Hallo???>> Es ging doch um den TO!>> Und nachdem der TO schon mit for(;;) Probleme hatte, glaubst du, dass er> dieses hier
Du bist des Lesens scheinbar auch nicht mächtig.
Nachdem schon eine ganze Reihe dämlicher #defines, etc. kam, habe ich
diese "Antwort" in den Ring geworfen. Sie reiht sich also ganz dort ein.
Allerdings hat sie schon Vorteile, wie manche hier bemerkt haben.
Apollo M. schrieb:> Wem muss ich hier um Erlaubnis fragen
Musst du nicht einmal im Akkusativ. :-) Schau einfach mal das
Eingangsposting, es hatte schlicht jemand gefragt, warum man sowas in
anderer Leute Sourcecode finden kann.
Klaus schrieb:> Probier es aus und teile uns deine Erkenntnisse mit.
Ich habe den Code eingegeben und auf Kompilieren geklickt.
Doch dann tat sich plötzlich hinter meinem Sofa ein riesiges Loch auf.
Es schlagen Flammen heraus und in der Ferne, ganz tief drin, höre ich
Schreie.
Das stand so nicht im K&R-Buch!
Ich warte mal ab. Vielleicht löst sich das ja von ganz alleine.
Da ich gestern in einem anderen Zusammenhang etwas Softwarearchäologie
betrieben habe, erinnerte ich mich auch daran, wie ich nach der Lektüre
des K&R (1. Auflage) meine ersten Gehversuche in C unternahm und schon
damals vor der Frage stand, ob ich für Endlosschleifen besser
1
for(;;)
oder
1
while(1)
schreiben sollte.
Neben der Tatsache, dass im K&R for(;;) explizit als mögliche
Schreibweise für Endlosschleifen aufgeführt war, machte ich mir auch
Gedanken darüber, was wohl der Compiler aus den beiden Varianten macht.
Irgendeiner der mir zur Verfügung stehenden Compiler (ich weiß nicht
mehr genau, welcher), nahm das while(1) tatsächlich wörtlich und
erzeugte Code, der zuerst eine 1 in ein Register lud, dieses Register
auf 0 prüfte und abhängig vom Ergebnis aus der Schleife heraussprang.
Bei for(;;) hingegen generierte er einfach den Schleifenrumpf gefolgt
von einem Sprung zum Schleifenanfang.
Bei den heutigen, optimierenden Compilern, muss man sich solche Gedanken
natürlich nicht mehr machen. Da wird sofort (beim GCC sogar mit -O0)
erkannt, dass die Bedingung 1 trivialerweise immer erfüllt ist und sie
deswegen komplett wegoptimiert werden kann.
Trotzdem frage ich mich, warum man für eine Schleife, deren Rumpf
bedingungs*LOS* immer und immer wieder ausgeführt werden soll, eine
Bedingung hinschreiben sollte, nur damit sie der Compiler bei der
Codegenerierung wieder entfernt.
Ich schreibe ja auch nicht
1
y=3+10*x*1+0;
obwohl ich fest davon ausgehen kann, dass das "* 1" und das "+ 0" vom
Compiler wegoptimiert wird.
Also lasse ich bei Endlosschleifen auch in Zukunft die Bedingung weg und
verwende deswegen weiterhin
Yalu X. schrieb:> Irgendeiner der mir zur Verfügung stehenden Compiler (ich weiß nicht> mehr genau, welcher), nahm das while(1) tatsächlich wörtlich und> erzeugte Code, der zuerst eine 1 in ein Register lud, dieses Register> auf 0 prüfte und abhängig vom Ergebnis aus der Schleife heraussprang.
Das war dann im letzten Jahrtausend.
> Trotzdem frage ich mich, warum man für eine Schleife, deren Rumpf> bedingungs*LOS* immer und immer wieder ausgeführt werden soll, eine> Bedingung hinschreiben sollte, nur damit sie der Compiler bei der> Codegenerierung wieder entfernt.
Bedingungs*los* ist es ja nicht... Die Bedingung ist eben immer wahr.
Bei for(;;) ist verwirrend, das eine leere Bedingung akzeptiert wird,
und diese immer wahr ist. Auch nicht intuitiv.
Johann L. schrieb:> Auch nicht intuitiv.
Meine Sprachgefühl und C lagen von Anfang an nicht so ganz in Deckung.
Lernen muss man die Sprache ohnehin, gerade auch hinsichtlich dessen,
was nicht ins Auge springt, wie undefined/unspeficied/... behaviour und
Umgang mit Typen verschiedener Breite. Da kommt es auf solchen Pipifax
wirklich nicht an.
Hallo,
das wollte ich auch soeben als Gegenkommentar schreiben. :-)
for benötigt auch eine Bedingung und für Endlos eben eine leere
Bedingung. Nur was ist eine leere Bedingung? Was will der Programmierer
mit "nichts" ausdrücken? Fragen über Fragen und deshalb wird es im
Forum auch ständig zu der Nachfrage kommen was for(;;) sein soll, wenn
das jemand liest.
Mit while(1) ist klar erkennbar das der Programmierer die Bedingung mit
"immer wahr" eindeutig konstant festgelegt hat. Das ist meine Logik.
> Ich schreibe ja auch nicht> y = 3 + 10 x 1 + 0;
Und selbst das kann sinnvoll sein, wenn man eine Formel mit
Wiedererkennungswert niederschreiben möchte. Pauschal ablehnen würde ich
sowas nicht.
Veit D. schrieb:> Und selbst das kann sinnvoll sein
Bei Mikrocontrollern kann es viel Sinn ergeben, wenn man eine 0 um N
Stellen nach links schiebt: ctrlreg = 1<<BITX | 0<<BITY.
> Bedingungs*los* ist es ja nicht...
Doch, das ist bedingungslos aka ein unconditional jump, also ein "goto".
"goto" hat hier gegenüber der entkernten Schleife den Vorteil das wegen
der Sprung-Marke der Umfang der Schleife klar erkennbar ist.
Bei einer (verschachtelten) Schleife dagegen muss man genau öffnende {
und schliessende Block-token} zählen. Das ist fehlerträchtig.
Besteht man aber darauf das es es doch eine Bedingung wäre die aber
zwanghaft true ist fabriziert man längeren Pseudocode, bspw.
CLEAR Reg
JMPZ Reg,L_START;
statt:
JMP L_START
Harald K. schrieb:> while (1)> {> label:> if (1)> continue;> else> continue;> goto label;> }
Den Fall, dass das goto nicht immer richtig funktioniert (Strahlen und
so!) würde ich auf jeden Fall noch mit abfangen:
MaWin O. schrieb:> Strahlen und so!
Die schaden bei sowas nur dem ohnehin schon vorverstrahlten
Programmierer. Die Hardware sieht nur den Binärcode, und der ist der
gleiche. ;-)
Johann L. schrieb:> Yalu X. schrieb:>>> Irgendeiner der mir zur Verfügung stehenden Compiler (ich weiß nicht>> mehr genau, welcher), nahm das while(1) tatsächlich wörtlich und>> erzeugte Code, der zuerst eine 1 in ein Register lud, dieses Register>> auf 0 prüfte und abhängig vom Ergebnis aus der Schleife heraussprang.>> Das war dann im letzten Jahrtausend.
Damals hatte ich auch mal einen Compiler, dessen Name ich nicht mehr
weiß: was ich aber noch ganz genau weiß,dass es für/while(true)/ den
optimalen Code erzeugt hat.
>> Trotzdem frage ich mich, warum man für eine Schleife, deren Rumpf>> bedingungs*LOS* immer und immer wieder ausgeführt werden soll, eine>> Bedingung hinschreiben sollte, nur damit sie der Compiler bei der>> Codegenerierung wieder entfernt.>> Bedingungs*los* ist es ja nicht... Die Bedingung ist eben immer wahr.
Das hatte ich oben schonmal geschrieben.
>> Bei for(;;) ist verwirrend, das eine leere Bedingung akzeptiert wird,> und diese immer wahr ist. Auch nicht intuitiv.
Auch das hätte ich oben angemerkt: es steht irgendwo versteckt im
C-Standard drin, und mitnichten intuitiv.
Man könnte genauso gut argumentieren, dass diese nicht vorhandene
Bedingung zu false evaluiert, um unbeabsichtigte Endlos-Iterationen zu
verhindern.
Wer ›goto‹ nachmacht oder verfälscht, oder nachgemachtes oder
verfälschtes ›goto‹ in Umlauf bringt, wird mit BASIC nicht unter drei
Portionen bestraft!
Parabelförmig vomittierend…
Johann L. schrieb:> Yalu X. schrieb:>>> Irgendeiner der mir zur Verfügung stehenden Compiler (ich weiß nicht>> mehr genau, welcher), nahm das while(1) tatsächlich wörtlich und>> erzeugte Code, der zuerst eine 1 in ein Register lud, dieses Register>> auf 0 prüfte und abhängig vom Ergebnis aus der Schleife heraussprang.>> Das war dann im letzten Jahrtausend.
Richtig:
Yalu X. schrieb:> nach der Lektüre des K&R (1. Auflage)
Das Buch habe ich zuvor neu im Buchhandel erworben :)
Johann L. schrieb:>> Trotzdem frage ich mich, warum man für eine Schleife, deren Rumpf>> bedingungs*LOS* immer und immer wieder ausgeführt werden soll, eine>> Bedingung hinschreiben sollte, nur damit sie der Compiler bei der>> Codegenerierung wieder entfernt.>> Bedingungs*los* ist es ja nicht... Die Bedingung ist eben immer wahr.
Zumindest in meinen Augen ist es bedingungslos, da die Ausführung des
Schleifenrumpfs immer erfolgt soll, also an keinerlei Bedingungen
geknüpft ist. Das true oder die 1 als Bedingungen kommt erst ins Spiel,
wenn man die Ausführung einer Anweisung eigentlich nicht an eine
Bedingung knüpfen möchte, aus rein formalen Gründen aber eine solche
verlangt wird. Genau dies ist bei while() der Fall, weil es die
Grammatik von C so vorschreibt, nicht aber bei for(), wo die Bedingung
optional ist.
Man könnte sich ein "cC" (conditional C) vorstellen, wo grundsätzlich
jede Anweisung an eine Bedingung geknüpft ist. Das würde dann bspw. so
aussehen:
1
x<lower_limit:>x=lower_limit;
2
x>upper_limit:>x=upper_limit;
3
true:>printf("lower_limit = %d\n",lower_limit);
4
true:>printf("x = %d\n",x);
5
true:>printf("upper_limit = %d\n",upper_limit);
In den ersten beiden Anweisungen ist die Bedingung erwünscht, die drei
nachfolgenden sollen aber bedingungslos ausgeführt werden. Die Grammatik
der Sprache verlangt aber nach einer Bedingung, also schreibt man eben
jeweils ein "true" hin, um den Compiler zufriedenzustellen. Wäre es
nicht schön, wenn die Bedingung optional wäre, so dass man den Code wie
folgt schreiben könnte:
1
x<lower_limit:>x=lower_limit;
2
x>upper_limit:>x=upper_limit;
3
printf("lower_limit = %d\n",lower_limit);
4
printf("x = %d\n",x);
5
printf("upper_limit = %d\n",upper_limit);
Oder meinst du, die drei leeren Bedingungen könnten von jemandem als
"false" interpretiert werden, was bedeuten würde, dass die printfs nie
ausgeführt würden?
cC ist zwar eine hypothetische Sprache, aber in ARM-Assembler kann fast
jede Instruktion bedingt ausgeführt werden (was natürlich auch von der
CPU-Hardware unterstützt wird), wobei die Bedingung durch einen
Zweizeichensuffix festgelegt wird, bspw.
1
MOVEQ ... ; Ausführung nur, wenn Z-Flag gesetzt ist
2
MOVHI ... ; Ausführung nur, wenn C-Flag gesetzt und Z-Flag gelöscht ist
3
MOVAL ... ; Ausführung immer (ALways)
4
MOV ... ; Ausführung immer
Der "AL"-Suffix entspricht also dem "true". Der Bedingungssuffix ist
optional. Wenn man ihn weglässt, wird die Instruktion immer ausgeführt.
Ich habe noch von niemandem gehört, der bei der bedingungslosen
Ausführung von Instruktionen auf dem "AL" bestehen würde mit der
Begründung, dass das Weglassen ja auch bedeuten könnte, dass die
Ausführung unterbunden wird.
Ja, ich weiß, die ganze Diskussion um das while(1) vs for(;;) ist
relativ müßig, und ich spucke ja auch niemanden an, der while(1)
verwendet ;-)
Yalu X. schrieb:> Zumindest in meinen Augen ist es bedingungslos, da die Ausführung des> Schleifenrumpfs immer erfolgt soll, also an keinerlei Bedingungen> geknüpft ist.
Für mich bedeutet das Fehlen der Bedingung, dass per Zufall entschieden
wird, ob die Schleife weiterläuft.
MaWin O. schrieb:> Für mich bedeutet das Fehlen der Bedingung, dass per Zufall entschieden> wird, ob die Schleife weiterläuft.
Weise Männer haben dereinst die sogenannten ›defaults‹ erfunden. Scheint
sich bewährt zu haben.
Norbert schrieb:> Weise Männer haben dereinst die sogenannten ›defaults‹ erfunden. Scheint> sich bewährt zu haben.
Was sind ›defaults‹?
Für mich ist die Sache glasklar: Durch das Auslassen der Bedingung
kommuniziert der Programmierer eindeutig, dass es ihm egal ist, unter
welcher Bedingung der Code ausgeführt wird (oder eben nicht ausgeführt
wird).
Eine konforme und zudem noch faire Implementierung dessen wäre die
Entscheidung per Zufallsgenerator.
MaWin O. schrieb:> Für mich bedeutet das Fehlen der Bedingung, dass per Zufall entschieden> wird, ob die Schleife weiterläuft.
Da du diese Aussage nicht an eine Bedingung (auch nicht an die immer
wahre) geknüpft hast, bleibt es also undefiniert, ob du sie wirklich so
meinst oder nicht ;-)
MaWin O. schrieb:> Eine konforme und zudem noch faire Implementierung dessen wäre die> Entscheidung per Zufallsgenerator.
Ok, ich habe gerade eine Münze entscheiden lassen. Ergebnis: Kopf. Also
meinst du das Gegenteil von dem, was du geschrieben hast ;-)
MaWin O. schrieb:> Was sind ›defaults‹?
Wo wir schon so Top-seriös bei Sache sind: wenn dir das Geld für eigene
Recherchen ausgegangen ist: Zahlungsverzug oder -Einstellung.
Norbert schrieb:> Möchtest du dafür gerne ein ›Let me google that for you‹ haben?
Nein. Aber dann scheint es ja unwichtig zu sein, wenn du es nicht einmal
für nötig hältst das kurz zu erklären.
Yalu X. schrieb:> Zumindest in meinen Augen ist es bedingungslos, da die Ausführung des> Schleifenrumpfs immer erfolgt soll, also an keinerlei Bedingungen> geknüpft ist.
Der TO ist das beste Beispiel dafür, dass das keineswegs klar ist.
Schreibt man es explizit hin, ist es doch sofort jedem klar! Wie gesagt:
wie in ganz vielen anderen Fällen ist explizit besser als implizit.
Yalu X. schrieb:> Ja, ich weiß, die ganze Diskussion um das while(1) vs for(;;) ist> relativ müßig, und ich spucke ja auch niemanden an, der while(1)> verwendet ;-)
Nach dem Sermon, den Du dazu schreibst, bin ich mir da gerade nicht so
sicher ...
Wilhelm M. schrieb:> Yalu X. schrieb:>> Zumindest in meinen Augen ist es bedingungslos, da die Ausführung des>> Schleifenrumpfs immer erfolgt soll, also an keinerlei Bedingungen>> geknüpft ist.>> Der TO ist das beste Beispiel dafür, dass das keineswegs klar ist.
Einer, der noch kein C-Buch durchgearbeitet hat, wird beim erstmaligen
Anblick von
1
while(1){
2
...
3
}
fragen: "Häh, was soll denn diese Schleife mit nur 1 Durchlauf? Warum
lässt man das while nicht einfach weg?"
Ich meine mich vage erinnern zu können, dass wir hier im Forum sogar
tatsächlich einmal einen ähnlichen Fall hatten.
Yalu X. schrieb:> Einer, der noch kein C-Buch durchgearbeitet hat, wird beim erstmaligen> Anblick von> while (1) {> ...> }
Wer schreibt denn heute noch so einen Blödsinn? Seit C99 heißt das
while(true).
Wilhelm M. schrieb:> Yalu X. schrieb:>> Einer, der noch kein C-Buch durchgearbeitet hat, wird beim erstmaligen>> Anblick von>> while (1) {>> ...>> }>> Wer schreibt denn heute noch so einen Blödsinn? Seit C99 heißt das> while(true).
Der Code, den der unwissende Anfänger vorgesetzt bekommt, könnte auch
schon älter sein.
Yalu X. schrieb:> Der Code, den der unwissende Anfänger vorgesetzt bekommt, könnte auch> schon älter sein.
In welchem Buch, etc. wird denn die /while/-Iteration mit einer
Zählschleife assoziiert? Jeder, der ein C-Buch mal in der Hand hatte,
weiß, dass dem nicht so ist. Die "Zählschleife" ist die /for/-loop.
Die Frage, die hier eigentlich nach dem Lesen des Buches entstehen
sollte, was ist denn "1" für ein Boole'scher Ausdruck? Ist damit "true"
gemeint?
(prx) A. K. schrieb:> K&R erste Fassung von 1978. Wer das durchlas, konnte es kaum übersehen.> Wer nicht, war selber Schuld.
Interessant, also ein leerer zweite Term genügt für ne endlos-schleife?!
Na dann, schauen wir mal wie schnell Chuck Norris mit unendlich durch
ist:
for (int *pt = malloc(0);;pt++) {}
o.ä.
Wilhelm M. schrieb:> Die Frage, die hier eigentlich nach dem Lesen des Buches entstehen> sollte, was ist denn "1" für ein Boole'scher Ausdruck?
Wenn man sich länger als fünf Minuten mit C beschäftigt haben sollte,
ist das keine Frage, die entsteht.
Wilhelm M. schrieb:> Yalu X. schrieb:>> Der Code, den der unwissende Anfänger vorgesetzt bekommt, könnte auch>> schon älter sein.>> In welchem Buch, etc. wird denn die /while/-Iteration mit einer> Zählschleife assoziiert?Yalu X. schrieb:> Einer, der noch kein C-Buch durchgearbeitet hat, ...
Du hast offensichtlich das Wörtchen "kein" überlesen. Einer, der das
Buch gelesen hat, weiß das natürlich. Er weiß dann aber auch, was
for(;;) bedeutet.
Yalu X. schrieb:> Du hast offensichtlich das Wörtchen "kein" überlesen.
Nein. Warum sollte denn der Ausdruck bei while die Anzahl(!) der
Durchläufe sein.
In deutsch: solange(1).
Wer kommt dabei auf die Idee, dass "1" die Anzahl der Iterationen sein
sollte?
Wilhelm M. schrieb:> Yalu X. schrieb:>> Du hast offensichtlich das Wörtchen "kein" überlesen.>> Nein. Warum sollte denn der Ausdruck bei while die Anzahl(!) der> Durchläufe sein.
Vielleicht, weil es jemand nicht besser weiß? Er sieht ein "while" und
hat vielleicht schon einmal irgendwoher gehört, dass das mit einer
Schleife zu tun hat. Dann sieht er noch eine Zahl (in diesem Fall die
1), und überlegt, welche Bedeutung eine Zahl im Schleifenkopf haben
könnte. Da ist es doch durchaus naheliegend, dass das die Anzahl der
Durchläufe sein könnte.
> In deutsch: solange(1).
Wer versucht, Programmcode zu verstehen, indem er ihn ins Deutsche
übersetzt, hat schon von vornherein verloren. Aus deinem favorisierten
while(true) würde solange(wahr). Ohne entsprechendes Vorwissen (bspw.
aus einem Buch) ist das so verständlich wie vorgestern(joghurtbecher).
Wilhelm M. schrieb:> Der TO ist das beste Beispiel dafür, dass das keineswegs klar ist.>
Jetzt muss ich doch noch anmerken, dass es mir schon klar war, dass es
sich um eine Endlosschleife handeln musste, nur gesehen hatte ich bisher
for(;;) noch nie. Die Firmware von Microchip, anfangs von mir erwähnt,
habe ich für meine Bedürfnisse abgeändert und sie funktioniert. Sie
treibt seit drei Jahren einen BLDC-Motor an.
Apropos bedingt, unbedingt:
Folgende Bedingung musste ich in eine andere Schleife einbinden, um den
Controller auszuschalten:
while(!PORTBbits.RB2)
{
blabla;
}
Yalu X. schrieb:> Wilhelm M. schrieb:>> Yalu X. schrieb:>>> Du hast offensichtlich das Wörtchen "kein" überlesen.>>>> Nein. Warum sollte denn der Ausdruck bei while die Anzahl(!) der>> Durchläufe sein.>> Vielleicht, weil es jemand nicht besser weiß?
Und derjenige weiß dann, dass for(;;) einen impliziten Bedingungsteil
hat, der immer true ist. Das glaubst Du doch selbst nicht.
>> In deutsch: solange(1).> Wer versucht, Programmcode zu verstehen, indem er ihn ins Deutsche> übersetzt, hat schon von vornherein verloren. Aus deinem favorisierten> while(true) würde solange(wahr).
Genau. Und das halte ich für ziemlich selbsterklärend.
Jan S. schrieb:> Jetzt muss ich doch noch anmerken, dass es mir schon klar war, dass es> sich um eine Endlosschleife handeln musste, nur gesehen hatte ich bisher> for(;;) noch nie.
Du hast es also aus dem Kontext geschlossen ...
Wilhelm M. schrieb:> Jan S. schrieb:>> Jetzt muss ich doch noch anmerken, dass es mir schon klar war, dass es>> sich um eine Endlosschleife handeln musste, nur gesehen hatte ich bisher>> for(;;) noch nie.>> Du hast es also aus dem Kontext geschlossen ...
Ja, die Firmware, die ich abgeändert habe, stammt aus einer noch älteren
Firmware als der anfangs gepostete Codeschnipsel. Im älteren
Codeschnipsel benutzte der Programmierer while(1){}.
Gruss Jan
Wilhelm M. schrieb:> Und derjenige weiß dann, dass for(;;) einen impliziten Bedingungsteil> hat, der immer true ist. Das glaubst Du doch selbst nicht.
Das einer, der noch kein C-Buch gelesen hat, das for- leichter als das
while-Konstrukt versteht, habe ich nirgends behauptet. Wenn er aber erst
einmal weiß, was die drei Teile der for-Schleifenkopfs bedeuten, wird er
aus dem Fehlen des mittleren Teils schließen, dass der Programmierer
keine Bedingung für die Ausführung des Schleifenrumpfs vorgesehen hat,
offensichtlich mit der Absicht, dass dieser bedingungslos, d.h. ohne
Einschränkungen ausgeführt wird. Fertig. Das ist alles, was er wissen
muss.
Er muss, um zu diesem Schluss zu kommen, nicht den Umweg über die
implizite, immer true liefernde Bedingung gehen, sondern den Begriff
"Bedingung" genauso wie im normalen Sprachgebrauch betrachten: Wenn ich
im realen Leben jemandem eine Zusage mache und knüpfe diese an keinerlei
Bedingung, dann lasse ich diese einfach weg.
Beispiel:
Zusage mit Bedingung:
"Wenn es schönes Wetter wird, werde ich dich morgen besuchen."
Zusage ohne Bedingung:
"Ich werde dich morgen besuchen."
und nicht etwa
"Wenn die immer erfüllte Bedingung erfüllt ist, werde ich dich morgen
besuchen."
oder
"Wenn wahr, werde ich dich morgen besuchen."
Es kann natürlich sein, dass dein Sprachgebrauch ein anderer ist als
meiner. Dann werde ich das natürlich akzeptieren.
Yalu X. schrieb:> aus dem Fehlen des mittleren Teils schließen, dass der Programmierer> keine Bedingung für die Ausführung des Schleifenrumpfs vorgesehen hat,> offensichtlich mit der Absicht, dass dieser bedingungslos
Eine Schleife wird aber leider nicht mit 'loop' eingeleitet, sondern mit
'for'.
for(;;)? for what? Das ergibt überhaupt keinen Sinn und gehört auf den
Müllhaufen der Geschichte.
Hallo,
eigentlich ist es mir ja egal wer was wie schreibt. Es ist nur
erschreckend mitzulesen was für abstruse Begründungen hier aufgefahren
werden um seine Ansicht irgendwie zu begründen. Wenn K&R damals for (;;)
nicht als Endlosschleife irgendwo niedergeschrieben hätten, wüßte bis
heute niemand das dieses unklare Konstrukt zur Endlosschleife mutiert.
Denn das geht aus der "for" Beschreibung allein nicht hervor. Das
for(;;) wird extra beschrieben das es eine Endlosschleife ist. Da kommt
sonst niemand drauf. Im Nachgang werden sich dann komische Begründungen
ausgedacht um das zurechtfertigen, wie man im Thread sehr schön
beobachten kann. Darüber muss ich mich schon sehr stark wundern. Im
Gegensatz zu while. Hieraus geht aus der Beschreibung schon hervor
solange die Bedingung wahr ist werden die Anweisungen wiederholt
ausgeführt.
> und nicht etwa> "Wenn die immer erfüllte Bedingung erfüllt ist, werde ich dich morgen> besuchen."
Tut mir leid, will dir nicht zu Nahe treten, aber ist auch nur eine
abstruse Begründung, eine verdrehte Satzbildung, dafür das du while eben
nicht leiden kannst und nicht akzeptierst.
Denn es muss lauten wie es im Lehrbuch steht.
Wenn die Bedingung erfüllt ist, werde ich dich morgen besuchen.
Oder besser.
Solange die Bedingung erfüllt ist, werde ich dich morgen besuchen.
Wie gesagt, verwendet was ihr wollt, aber hört auf Euch irgendwelche
lächerlichen Begründungen für irgendwas auszudenken. Nur weil K&R damals
nichts besseres einfiel und ihr das nun gewohnt seit und verwendet. Der
Fortschritt lebt davon eingeschliffene Dinge zu hinterfragen. Die
gesamte Haarspalterei im Thread ist lächerlich.
Ahmen.
Veit D. schrieb:> Im Nachgang werden sich dann komische Begründungen ausgedacht um das> zurechtfertigen, wie man im Thread sehr schön beobachten kann.
Ja, irgendwie muss der Thread doch seine Endlosschleife hier weiter
fahren, oder?
Yalu X. schrieb:> ...> Er muss, um zu diesem Schluss zu kommen, nicht den Umweg über die> implizite, immer true liefernde Bedingung gehen, sondern den Begriff> "Bedingung" genauso wie im normalen Sprachgebrauch betrachten: Wenn ich> im realen Leben jemandem eine Zusage mache und knüpfe diese an keinerlei> Bedingung, dann lasse ich diese einfach weg.>> Beispiel:> "Wenn wahr, werde ich dich morgen besuchen.">> Es kann natürlich sein, dass dein Sprachgebrauch ein anderer ist als> meiner. Dann werde ich das natürlich akzeptieren.Yalu X. schrieb:> Wer versucht, Programmcode zu verstehen, indem er ihn ins Deutsche> übersetzt, hat schon von vornherein verloren. Aus deinem favorisierten> while(true) würde solange(wahr). Ohne entsprechendes Vorwissen (bspw.> aus einem Buch) ist das so verständlich wie vorgestern(joghurtbecher).
Yalu X. schrieb:> Yalu X. schrieb:>> nach der Lektüre des K&R (1. Auflage)
Ich bezweifle, dass dieses Buch heute noch gelesen wird. Und doch, würde
ich dem Kandidaten empfehlen, damit aufzuhören.
Sonst diskutieren wird demnächst noch über die Funktionsdeklaration im
K&R-Stil bzw. darüber, dass es doch viel einfacher sei, eine Deklaration
ohne Parameterliste zu schreiben, und das es eben besser sei, nur
Funktionen zu deklarieren, die kein int zurück geben.
Je länger Eure Begründungstexte werden, desto abstruster werden sie.
Jan S. schrieb:> Wilhelm M. schrieb:>> Jan S. schrieb:>>> Jetzt muss ich doch noch anmerken, dass es mir schon klar war, dass es>>> sich um eine Endlosschleife handeln musste, nur gesehen hatte ich bisher>>> for(;;) noch nie.>>>> Du hast es also aus dem Kontext geschlossen ...> Ja, die Firmware, die ich abgeändert habe, stammt aus einer noch älteren> Firmware als der anfangs gepostete Codeschnipsel. Im älteren> Codeschnipsel benutzte der Programmierer while(1){}.> Gruss Jan
Intressant:
ursprünglich stand dort also ein while, dass irgendjemand zu einem
/for(;;)/ verschlimmbessert hat. Und das machte dann Deine
Verständnisschwierigkeiten.
> Wenn er aber erst> einmal weiß, was die drei Teile der for-Schleifenkopfs bedeuten, wird er> aus dem Fehlen des mittleren Teils schließen, dass der Programmierer> keine Bedingung für die Ausführung des Schleifenrumpfs vorgesehen hat,> offensichtlich mit der Absicht, dass dieser bedingungslos, d.h. ohne> Einschränkungen ausgeführt wird. Fertig.
.. ist der Syntax-fehler.
OK, hier gerade nicht, aber eben nur weil der Compiler die
Zusatzanforderung - nichts angegeben, ist das gleich wie 1 == 1
reingeschrieben - kennt. An allen möglichen Stellen meckert/warnt der
Compiler, das hier und da dem Syntax irgendetwas fehlen könnte (i.e.
"Read before written" oder if (a = 0)) aber in diesem Semikolonsalat
zaubert er irgendeine prähistorische Regel aus dem Hut, die
Alltagsdenken komplett widerspricht ("Mach etwas bis in alle Ewigkeit
auch wenn Du nicht explizit dazu aufgeforderst wird").
Siehe auch:
https://youtu.be/NgUSe5JpdoU?t=10
Für den Alltag dagegen lernt man, das "nichts sagen" auch nichts
bedeutet (rechtliches Nullum).
https://de.wikipedia.org/wiki/Schweigen_(Recht)
Wer aus dem Fehlen von Angaben auf irgendetwas schliessen will, sollte
wegen aufkeimenden verfolgungswahn zum Psychiater gehen.
Veit D. schrieb:> Wie gesagt, verwendet was ihr wollt, aber hört auf Euch irgendwelche> lächerlichen Begründungen für irgendwas auszudenken. Nur weil K&R damals> nichts besseres einfiel und ihr das nun gewohnt seit und verwendet.
Sehe ich auch so, hatte ich oben so geschrieben:
Wilhelm M. schrieb:> Hört sich fast so an, als wärt ihr katholisch: nur weil das vor Äonen> schon mal im K&R stand, bedeutet das (für mich) nicht, dass man das so> machen sollte. Ich denke da lieber selbst ;-)
Ist das die arabische Version von Amen ?
> Ahmen.
Wilhelm M. schrieb:> Je länger Eure Begründungstexte werden, desto abstruster werden sie.
Das ist der Sinn der Sache. Kann man fehlenden Humor eigentlich
nachlernen, oder muss man für den Rest des Lebens mit dem zurecht
kommen, was man in der Kindheit verpasste?
[offtopic]
> Ist das die arabische Version von Amen ?>> Ahmen.
Amen ist schon vom Wortursprung her arabisch resp. semitisch.
https://de.wikipedia.org/wiki/Amen#Etymologie
Lediglich die Schreibweisen variieren je nach bevorzugten Schriftsatz:
Lautschrift [ˈaːmɛn], hebräisch אָמֵן, altgriechisch ἀμήν, arabisch
آمين
[/offtopic]
DSGV-Violator schrieb:> [offtopic]>>> Ist das die arabische Version von Amen ?>>> Ahmen.>> Amen ist schon vom Wortursprung her arabisch resp. semitisch.
Danke, aber das es hebräisch ist, war mir schon klar.
> Lediglich die Schreibweisen variieren je nach bevorzugten Schriftsatz:> Lautschrift [ˈaːmɛn], hebräisch אָמֵן, altgriechisch ἀμήν, arabisch> آمين
Wikipedia kann ich selber lesen ;-)
Und in deutsch wird es üblicherweise als "Amen" geschrieben.
Wilhelm M. schrieb:> Und in deutsch wird es üblicherweise als "Amen" geschrieben.
Keine Sorge, das kommt noch. Sprache pflegt sich den veränderten
Gegebenheiten anzupassen.
MaWin O. schrieb:> Yalu X. schrieb:>> aus dem Fehlen des mittleren Teils schließen, dass der Programmierer>> keine Bedingung für die Ausführung des Schleifenrumpfs vorgesehen hat,>> offensichtlich mit der Absicht, dass dieser bedingungslos>> Eine Schleife wird aber leider nicht mit 'loop' eingeleitet, sondern mit> 'for'.
Da stimme ich dir zu. Mit "loop" wäre das Ganze noch ein Stückchen
besser. Und bei while(true) könnte dann wie in Rust eine Warning (oder
noch besser ein Error) ausgegeben werden.
Wilhelm würde aber vermutlich auch loop ablehnen mit der Begründung,
dass loop nichts anderes als while(true) mit einer böswillig
versteckten, impliziten und immer wahren Bedingung ist ;-)
Das ist ja mal ein ungewöhnlich lehrreicher Thread. Ich lerne daraus:
Endlosschleifen sind den Aufwand nicht wert, man verwendet einen
Thread/Task/Prozess, der immer wieder neu gestartet wird. Im
"Betriebssystem" darf es sowieso keine Endlosschleife geben, Problem
gelöst ;)
177 (178 jetzt) Beiträge über for (;;){} - DAS Anfängerstatement in C an
sich.
Dieses Forum ist so was von krank. Diskussion über die Endlosschleife in
einer Endlosschleife. Man könnte noch einen neuen Fred aufmachen, wo man
über die endlose Diskussion über die Diskussion der Endlosschleife
diskutiert?
Harald K. schrieb:> Erwähnte ich schon die beeindruckende Dichte geistiger Onanie in diesem> Thread hier?
Ja, jetzt schon zum dritten Mal. Das wird doch nicht etwa eine
Endlosschleife?
Bauform B. schrieb:> Im> "Betriebssystem" darf es sowieso keine Endlosschleife geben, Problem> gelöst ;)
Ich betrachte die ganz am Anfang gepostete Schleife als unbedingt
notwendig, sie ist das eigentliche "Betriebssystem", sie fragt pausenlos
den Zustand des Tasters ab, der restliche Betrieb läuft praktisch nur
noch über Interrupts.
Jan S. schrieb:> Bauform B. schrieb:>> Im>> "Betriebssystem" darf es sowieso keine Endlosschleife geben, Problem>> gelöst ;)>> Ich betrachte die ganz am Anfang gepostete Schleife als unbedingt> notwendig, sie ist das eigentliche "Betriebssystem", sie fragt pausenlos> den Zustand des Tasters ab, der restliche Betrieb läuft praktisch nur> noch über Interrupts.
Und warum darf der Taster keinen Interrupt liefern?
Bauform B. schrieb:> Und warum darf der Taster keinen Interrupt liefern?
Das könnte man schon auch über einen Interrupt machen, dann wäre das
Programm(oder "Betriebssystem") eine leere Endlosschleife.
Yalu X. schrieb:> MaWin O. schrieb:>> Yalu X. schrieb:>>> aus dem Fehlen des mittleren Teils schließen, dass der Programmierer>>> keine Bedingung für die Ausführung des Schleifenrumpfs vorgesehen hat,>>> offensichtlich mit der Absicht, dass dieser bedingungslos>>>> Eine Schleife wird aber leider nicht mit 'loop' eingeleitet, sondern mit>> 'for'.>> Da stimme ich dir zu. Mit "loop" wäre das Ganze noch ein Stückchen> besser. Und bei while(true) könnte dann wie in Rust eine Warning (oder> noch besser ein Error) ausgegeben werden.>> Wilhelm würde aber vermutlich auch loop ablehnen mit der Begründung,> dass loop nichts anderes als while(true) mit einer böswillig> versteckten, impliziten und immer wahren Bedingung ist ;-)
Wieso sollte ich das ablehnen? Anscheinend hast Du immer noch gar nichts
verstanden.
Ein
> wäre doch super.
Aber nur in einem mickrigen Drei-Zeilen Codeschnipsel.
Erstreckt sich der Schleifenköper aber über mehr als nur 40 Zeilen und
umschliesst als Schachtel weitere Blöcke und steckt womöglich selbst in
ein paar verschachtelten Schachtel-Blöcken reichen '{' und '}' als
Orientierung für Anfang und Ende nicht aus. Da sind Label und oder
comments handreichender. Aber offensihtlich sind Labels wie goto die
ungeliebten Stiefkinder in C.
https://www.geeksforgeeks.org/local-labels-in-c/
for(;;) musste ich erst nachschlagen und macht für mich auch keinen
wirklichen Sinn weil ich nicht davon ausgehen kann, dass das weglassen
von Argumenten automatisch zu einer Endlosschleife führt. Ohne Internet
wäre ich also aufgeschmissen.
while(1) oder while(true) ist auf Anhieb klar, wenn man halbwegs weiß
wie while funktioniert.
Ich schreibe daher auch
Hallo,
Veit D. schrieb:> Wenn K&R damals for (;;) nicht als Endlosschleife irgendwo> niedergeschrieben hätten...
Tja, haben sie eigentlich gar nicht. Ich habe mal in in der deutschen
Übersetzung von "Programmieren in C" von 1990 nachgesehen. Da wird in
Kapitel 3.5 "Schleifen - while und /for/" die entsprechende Syntax
beschrieben und darauf hingewiesen das beide Schleifenkonstrukte
zueinander äquivalent sind:
1
for ( expr1 ; expr2 ; expr3 )
2
statement
ist äquivalent zu
1
expr1 ;
2
while ( expr2 ) {
3
statement;
4
expr3;
5
}
Weiterhin heißt es (wurde hier auch schon des Öfteren erwähnt): "Fehlt
die Bedingung expr2, so gilt sie immer als wahr". Als _*Beispiel*_ wird
jetzt
1
for (;;) {
2
...
3
}
angeführt, Zitat "...ist also eine 'unendliche Schleife', die vermutlich
durch Anweisungen wie break oder return beendet wird". Und weiter
heißt es :"Ob man while oder for bevorzugt, beruht weitgehend auf
persönlicher Vorliebe."
Ich habe auch nirgend wo sonst im Buch eine explizite Forderung gefunden
das man für Endlosschleifen das for()-Konstrukt zu verwenden hat. Es
bleibt also jedem selbst überlassen welches Konstrukt er für seine
"Endlosschleifen" benutzt.
> ...wüßte bis heute niemand das dieses unklare Konstrukt zur> Endlosschleife mutiert.
Ich weiß noch genau wie ich zum ersten mal eine while(1) in einem
Quelltext gesehen und ich mich gewundert habe wie das funktioniert wo
doch der sonst üblich Vergleichsausdruck fehlt. Auch heute noch finde
ich diese Form der Endlosschleife merkwürdig, unlogisch und für einen
Anfänger schwer zu verstehen.
rhf
P.S.
Und im Übrigen bin ich der Meinung, das die Konstruktion von
Endlosschleifen mit while() oder for() die eigentliche Funktion
verschleiert. Deshalb ist für mich die einzig wahre Konstruktion die
mit
1
Label:
2
...
3
goto Label
Wenn dann noch Label entsprechend benannt wird, weiß jeder sofort und
unmissverständlich was gemeint ist
Hallo,
Wilhelm M. schrieb:> Aufgrund der obigen Diskussion muss ich natürlich noch den C++-Vorschlag> von oben
Warum? Wozu ist das gut, wo es doch hier um eine for(;;) in C geht?
rhf
DSGV-Violator schrieb:> lies das Buch über Endlos geflochtene Bänder - in den Achtzigern> schaffte es dieses sogar Wochenlang auf die Spiegel-Bestsellerliste:
Ich fragte mich allerdings schon damals, wieviele derer, die es gekauft
hatten, es auch in signifikantem Umfang gelesen hatten.
(prx) A. K. schrieb:> DSGV-Violator schrieb:>> lies das Buch über Endlos geflochtene Bänder - in den Achtzigern>> schaffte es dieses sogar Wochenlang auf die Spiegel-Bestsellerliste:>> Ich fragte mich allerdings schon damals, wieviele derer, die es gekauft> hatten, es auch in signifikantem Umfang gelesen hatten.
Nun, das Bemerkenswerte an diesem Buch ist, dass sich, aufgrund der
zahlreichen Zeichnungen von, den Buchtitel mit-tragenden, Maurits
Cornelis Escher, ein Zugang allein durch Betrachtung der Illustration
eine Zugangsmöglichkeit ergibt.
Andere mögen sich das Buch über die Ausführungen zur Musikgeschichte
(Bach) erschliessen, persönlich führte der Weg über die Ausführungen zur
formalen Logik und (Östlicher) Philosophie.
Die Darstellungen zum maschinellen Rechnen/Computerei funktionieren da
anschauliche beispiele zu einem (sehr) abstrakten) Thema.
Aber das Buch ist tatsächlich keine kleine Kost die man so nebenher bei
der Fahrt im ÖPNV "wegfuttert". Manche lesen ein Leben lang immer mal
wieder darin. Fast so wie die "Bibelforscher" ;-)
(prx) A. K. schrieb:> Jan S. schrieb:>> Jetzt wollte ich es noch vom C30-Compiler von Microchip wissen>> Ernsthaft anders erwartet?
Nein, aber es gibt Gewissheit...
DSGV-Violator schrieb:> Aber nur in einem mickrigen Drei-Zeilen Codeschnipsel.> Erstreckt sich der Schleifenköper aber über mehr als nur 40 Zeilen und> umschliesst als Schachtel weitere Blöcke und steckt womöglich selbst in> ein paar verschachtelten Schachtel-Blöcken reichen '{' und '}' als> Orientierung für Anfang und Ende nicht aus.
Schon mal was von Funktionen gehört?
M. D. schrieb:> y = x > 9 ? 100 : 200;
Der ternäre Operator ist in C nur eine "verkümmperte Lambda-Expression"
und in einer Wertzuweisung schon fehl am Platz, weil ein normales
/if/-statement besser zu lesen ist. Er ist allerdings wichtig für
Initialisierungen von read-only Objekten, etwa:
Roland F. schrieb:> Tja, haben sie eigentlich gar nicht. Ich habe mal in in der deutschen> Übersetzung von "Programmieren in C" von 1990 nachgesehen. Da wird in> Kapitel 3.5 "Schleifen - while und /for/" die entsprechende Syntax> beschrieben und darauf hingewiesen das beide Schleifenkonstrukte> zueinander äquivalent sind:
Ach was, schon mal was von Schleifentransformation gehört?
Roland F. schrieb:> ch weiß noch genau wie ich zum ersten mal eine while(1) in einem> Quelltext gesehen und ich mich gewundert habe wie das funktioniert wo> doch der sonst üblich Vergleichsausdruck fehlt.
Das ganz einfach an dieser dummen Praxis while(1) statt besser
while(true) hinzuschreiben.
Wilhelm M. schrieb:> und in einer Wertzuweisung schon fehl am Platz, weil ein normales> /if/-statement besser zu lesen ist.
Es kann zum Glück auch auf den Misthaufen der Geschichte.
In Rust kann das if-statement beides.
> Das ganz einfach an dieser dummen Praxis while(1) statt besser> while(true) hinzuschreiben.
Naja, das Dumme ist, das Standard-C in der Praxis keine boolean Werte
wie 'true' kennt.
Ist halt einer der Geburtsfehler dieser Sprache. Oder eben nicht, kommt
darauf an, ob man C eher als gezuckerten Assembler für Embedded oder als
Hochsprache für Mathematisch-Abstrakte Aufgabenstellungen die sich wenig
um numerische Representation schert, versteht/benutzt.
Beitrag "Boolean in C"> Schon mal was von Funktionen gehört?
Klar, würde hier u.a. wegen Context-switch/Stack-Operationen das Problem
noch vergrößern statt verkleinern.
DSGV-Violator schrieb:> Naja, das Dumme ist das Standard-C in der Praxis keine boolean Werte wie> true kennt.
Ja, C ist in vielerlei Hinsicht dumm! Siehe for(;;).
DSGV-Violator schrieb:>> Schon mal was von Funktionen gehört?> Klar, würde hier u.a. wegen Context-switch/Stack-Operationen das Problem> noch vergrößern statt verkleinern.
Hä???
DSGV-Violator schrieb:> Ich hau mich weg, das steht "removed in C23". Und> "Bequemlichkeits-Makro", die reinste Warmduscherei ..
Richtig, dafür ist es ab C23 ein eigener Typ.
MaWin O. schrieb:> DSGV-Violator schrieb:>> Ich hau mich weg>> Freut mich, dass du dich auch über kleine Dinge amüsieren kannst.
Über den Unterschied zwischen "Weg Hauen" und "Amüsement" müsste man
sich mal in Ruhe unterhalten ...
Ich finde es jedenfalls nicht hilfreich, das hier die Benutzung von
"abgeschnittenen Sonderlocken" aus Gründen der Bequemlichkeit
vorgeschlagen wird.
DSGV-Violator schrieb:> Ich finde es jedenfalls nicht hilfreich, das hier die Benutzung von> "abgeschnittenen Sonderlocken" aus Gründen der Bequemlichkeit> vorgeschlagen wird.
Kann es sein, dass es an deinem Leseverständnis hapert?
Wilhelm M. schrieb:>> Naja, das Dumme ist, das Standard-C in der Praxis keine boolean Werte>> wie 'true' kennt.> Mindestens seit C99 aber schon.> Richtig, dafür ist es ab C23 ein eigener Typ.
Alter Falter, nicht mal Jahreszahlen kriegt man hier richtig gebacken
...
Ja klar, in irgendeinem Standard von anno
"AchHatDerHundDieEckeMitDerJahreszahlGefressen" steht es so oder doch
anders und warum schreibt man überhaupt "Standards" wenn man diese wie
politische Parteien je nach Wahlkampf umfrisiert ...
Geburtsfehler ist nun mal Geburtsfehler, da kann auch plastische
Chirurgie nur den Anschein aufhübschen aber nicht den Wesenskern.
DSGV-Violator schrieb:> Alter Falter, nicht mal Jahreszahlen kriegt man hier richtig gebacken
Ab C99 gibt es bool, true und false, die sich wie echte Booleans
verhalten. Also nur die Werte 0 und 1 annehmen können. Was brauchst du
noch?
MaWin O. schrieb:> Ab C99 gibt es bool, true und false, die sich wie echte Booleans> verhalten. Also nur die Werte 0 und 1 annehmen können. Was brauchst du> noch?
Wie jetzt? Es muss doch heissen "nur die Werte zwischen 0.0 und 1.0".
Wie will man sonst die-ganze-Wahrheit von der einfachen Aussage
unterscheiden? Hier ist for(;;) auch wieder überlegen, weil, wie lange
läuft eine Endlosschleife while(true) mit true = 0.99?
DSGV-Violator schrieb:> Es gibt da schon einen Unterschied zwischen Sprache und> Standardbibliotheken.
Aus Sicht des Sprachstandards nicht wirklich, beides ist "the
implementation".
Dass man "true" und "false" so spät nicht einfach ohne Headerfile neu
definieren durfte, ist einfach mal den vielen existierenden Programmen
geschuldet, die sowas vorher selbst definiert haben durften. Der Typ
_Bool ist aber dennoch intrinisch, denn dessen Bezeichner liegt im
implementation namespace. <stdbool.h> mappt ihn dann nur auf bool.
Veit D. schrieb:> Wenn K&R damals for (;;)> nicht als Endlosschleife irgendwo niedergeschrieben hätten, wüßte bis> heute niemand das dieses unklare Konstrukt zur Endlosschleife mutiert.> Denn das geht aus der "for" Beschreibung allein nicht hervor. Das> for(;;) wird extra beschrieben das es eine Endlosschleife ist. Da kommt> sonst niemand drauf.
Das ist natürlich Quadratunsinn!
Im K&R steht es EXPLIZIT drin.
K&R Ed.2 page 56
Hans H. schrieb:> Ich schreibe die Endlosschleife immer so:> do {> // many> // lines> // of> // code> } while (1=1);>> denn ich finde die Überraschung muß am Ende kommen.
Parabelförmig vomittierend…
Wilhelm M. schrieb:> Ist das die arabische Version von Amen ?>> Ahmen.
Klarer Syntaxfehler von mir. Davor hätte mich bestimmt der Compiler
gewarnt. Mir fehlt nur noch eine Begründung wie man das doch noch als
Richtig erklären könnte. Dann wäre es Thread Konform. :-) :-)
Yalu X. schrieb:> Das true oder die 1 als Bedingungen kommt erst ins Spiel,> wenn man die Ausführung einer Anweisung eigentlich nicht an eine> Bedingung knüpfen möchte, aus rein formalen Gründen aber eine solche> verlangt wird.
Genau das meinte ich weiter oben, als ich davon sprach, dass es keine
richtige Bedingung sei. Technisch ist es natürlich eine Bedingung, aber
ich schreibe sie nur hin, weil sie eben formal nötig ist und nicht, weil
ich tatsächlich eine will.
DSGV-Violator schrieb:> Erstreckt sich der Schleifenköper aber über mehr als nur 40 Zeilen und> umschliesst als Schachtel weitere Blöcke und steckt womöglich selbst in> ein paar verschachtelten Schachtel-Blöcken
… dann sollte man sich mal schleunigst daran machen, den Code sauberer
zu strukturieren.
Wilhelm M. schrieb:> Auch das hätte ich oben angemerkt: es steht irgendwo versteckt im> C-Standard drin, und mitnichten intuitiv.
Wo das im C-Standard steht, wird für die wenigsten relevant sein, weil
sie da eh nicht reinschauen. Wichtiger ist, wo es im Lehrbuch steht, und
die Optionaliät der drei Ausrücke in einer for-Schleife wird da doch
hoffentlich im Kapitel über Schleifen drin stehen, sonst taugt es nicht
viel.
Und ich finde es im übrigen sehr wohl intuitiv, mehr noch als wenn ich
irgendwas als Bedingung hinschreiben muss, nur um der Form genüge zu
tun.
> Man könnte genauso gut argumentieren, dass diese nicht vorhandene> Bedingung zu false evaluiert, um unbeabsichtigte Endlos-Iterationen zu> verhindern.
Das wäre nun wirklich an den Haaren herbeigezogen. Warum hätten sie die
Bedingung dann überhaupt optional gemacht? Eine extra eingebaute
zusätzliche Option, nur um explizit Schleifen schreiben zu können, die
niemals ausgeführt werden? Das ergäbe nun wirklich gar keinen Sinn.
Wilhelm M. schrieb:> Yalu X. schrieb:>> Zumindest in meinen Augen ist es bedingungslos, da die Ausführung des>> Schleifenrumpfs immer erfolgt soll, also an keinerlei Bedingungen>> geknüpft ist.>> Der TO ist das beste Beispiel dafür, dass das keineswegs klar ist.
Hier hat jetzt genau einer mal nachgefragt. Es gibt hier zu allerhand
Bestandteilen verschiedener Sprachen Fragen. Das bedeutet nicht, dass
das alles völlig unintuitiv ist.
> Schreibt man es explizit hin, ist es doch sofort jedem klar! Wie gesagt:> wie in ganz vielen anderen Fällen ist explizit besser als implizit.
Bis auf das "es" sind wir uns da einig. Für mich ist "es" die
Bedingungslosigkeit der Schleife, denn das ist es ja, was ich eigentlich
erreichen will. Und Bedingungslosigkeit drückt man am besten dadurch
aus, dass man keine Bedingung angibt.
Wilhelm M. schrieb:> iterate(Forever{})([]{> r *= 2;> });
Was lisp kann (Klammernorgien), das bekommen wir in C++ doch auch locker
hin. ;-)
Yalu X. schrieb:> Harald K. schrieb:>> Erwähnte ich schon die beeindruckende Dichte geistiger Onanie in diesem>> Thread hier?>> Ja, jetzt schon zum dritten Mal. Das wird doch nicht etwa eine> Endlosschleife?
Was er vergessen hat zu erwähnen ist, warum er eigentlich immer noch
mitliest, wenn er die Diskussion so blöd findet.
Rolf M. schrieb:> Bis auf das "es" sind wir uns da einig. Für mich ist "es" die> Bedingungslosigkeit der Schleife, denn das ist es ja, was ich eigentlich> erreichen will.
Wenn Du explizit das Fehlen von etwas hinschreiben möchtest, dann
brauchst Du dafür eben ein Konstrukt, was Du schreiben kannst.
Also etwa:
1
for(;Unconditional{};){
2
3
}
Könnte man natürlich (in C++) machen. Oder in C eben mit for(;"ever";);
Wenn Du etwas weglässt, ist es eben nicht mehr explizit, sondern
implizit.
Rolf M. schrieb:> Wilhelm M. schrieb:>> iterate(Forever{})([]{>> r *= 2;>> });>> Was lisp kann (Klammernorgien), das bekommen wir in C++ doch auch locker> hin. ;-)
Während in Lisp hauptsächlich runde Klammern verwendet werden, kann man
in C++ alle Klammersymbole, die ASCII hergibt, also ()[]{}<>, fast nach
Belieben mischen.
Ich würde übrigens im obigen Lambda-Ausdruck die leere und deswegen
optionale Parameterliste explizit hinschreiben, weil sonst – ähnlich wie
bei der weggelassenen Bedingung in for(;;) – überhaupt nicht klar ist,
was der Compiler dafür einsetzt. Also so:
1
iterate(Forever{})([](){
2
// \___ ___/
3
// V
4
// 9, wow
Wilhelm schafft es sicher auch noch, das Beispiel mit ein paar
Template-Klammern (<>) aufzuhübschen, dann sind wir nicht mehr weit weg
von der Programmiersprache ], die zu einem würdigen Nachfolger von C++
werden könnte:
https://esolangs.org/wiki/Right_bracket
Wilhelm M. schrieb:> Wenn Du explizit das Fehlen von etwas hinschreiben möchtest,
Es fehlt doch aber nichts.
> dann brauchst Du dafür eben ein Konstrukt, was Du schreiben kannst.
Warum sollte ich was hinschreiben müssen, um damit auszudrücken, dass es
eigentlich nichts zum hinschreiben gibt?
C11/No Standard Library
Autosar19:
note 9177: condition of 'while' statement has non-Boolean type 'int'
[AUTOSAR Rule A5-0-2]
info 716: infinite loop via while
MISRA C 2012:
note 9036: essential type of condition of 'while' statement is 'signed8'
but should be boolean [MISRA 2012 Rule 14.4, required]
info 716: infinite loop via while
Die Info 716 wird immer getriggert, also nach MISRA und Autosar ist
while(1) praktisch doppelt böse. :-)
BARR-C 2018 hatte ich ja schon erwähnt.
Im SEI CERT C Coding Standard habe ich spontan nichts gefunden, also im
Netz, die Präferenz scheint da aber bei while(true) zu liegen.
1
#include <stdbool.h>
2
3
int main(void)
4
{
5
while (true)
6
{
7
}
8
}
MISRA C 2012:
info 716: infinite loop via while
supplemental 893: expanded from macro 'true' (line 17)
Interessant fände ich jetzt noch andere Beispiel von Coding Guidelines.
Ich habe gerade die ISO/IEC 17961 gefunden, bzw. natürlich nur den
Hinweis und nicht den Standard selber.
https://www.iso.org/standard/61134.html
Rudolph R. schrieb:> Interessant fände ich jetzt noch andere Beispiel von Coding Guidelines.
Ich bin erschüttert. Richtige Betriebssysteme brauchen Endlosschleifen,
aber die NASA nicht.
1
C Style and Coding Standards for SunOS
2
Bill Shannon
3
Copyright 1993 by Sun Microsystems, Inc.
4
5
for statements
6
for (initialization; condition; update) { statements; }
7
When using the comma operator in the initialization or update clauses
8
of a for statement, it is suggested that no more than three variables
9
should be updated. More than this tends to make the expression too
10
complex. In this case it is generally better to use separate
11
statements outside the for loop (for the initialization clause),
12
or at the end of the loop (for the update clause).
13
14
The infinite loop is written using a for loop.
15
for (;;) { statements; }
1
/*
2
* The NetBSD source code style guide.
3
* (Previously known as KNF - Kernel Normal Form).
4
*
5
* from: @(#)style 1.12 (Berkeley) 3/18/94
6
*/
7
/* Forever loops are done with for's, not while's. */
1
C STYLE GUIDE, AUGUST 1994
2
SOFTWARE ENGINEERING LABORATORY SERIES SEL-94-003
3
National Aeronautics and Space Administration
4
Goddard Space Flight Center
5
Greenbelt, Maryland 20771
Dieses 100-Seiten Werk erwähnt solche Schleifen mit keiner Silbe.
Edit: linux-source-4.19/Documentation/process/coding-style.rst schreibt
auch nichts vor.
Yalu X. schrieb:> Während in Lisp hauptsächlich runde Klammern verwendet werden, kann man> in C++ alle Klammersymbole, die ASCII hergibt, also ()[]{}<>, fast nach> Belieben mischen.
Das geht in C auch ;-) Allerdings ist in C die Wahrscheinlichkeit, dass
sich dadurch ein valides C Programm ergibt, geringer.
> Ich würde übrigens im obigen Lambda-Ausdruck die leere und deswegen> optionale Parameterliste explizit hinschreiben, weil sonst – ähnlich wie> bei der weggelassenen Bedingung in for(;;) – überhaupt nicht klar ist,> was der Compiler dafür einsetzt.
Leider falsch.
Wenn Du in for(;true;) oder for(;false;) den Boole'schen Wert weglässt,
wird dafür (in C) ein implementation-defined Wert != 0 eingesetzt.
Wenn Du in dem Lambda-Ausdruck [](){} die leere Parameterliste weglässt,
wird die durch nichts, auch nichts anderes ersetzt.
Also so:
> iterate(Forever{})([](){> // \___ ___/> // V> // 9, wow>> Wilhelm schafft es sicher auch noch, das Beispiel mit ein paar> Template-Klammern (<>) aufzuhübschen,
Hatte ich doch schon, oder?
Bauform B. schrieb:> Rudolph R. schrieb:>> Interessant fände ich jetzt noch andere Beispiel von Coding Guidelines.>> Ich bin erschüttert. Richtige Betriebssysteme brauchen Endlosschleifen,> aber die NASA nicht.
Naja es gibt halt neben "richtigen" Betriebssystemen auch
Betriebssysteme die im Space steuerbar sein müßen. Da sind
Endlosschleifen das letzte was man will, siehe bspw. WatchDogtimer.
DSGV-Violator schrieb:> Naja es gibt halt neben "richtigen" Betriebssystemen auch> Betriebssysteme die im Space steuerbar sein müßen. Da sind> Endlosschleifen das letzte was man will, siehe bspw. WatchDogtimer.
Nun, wenn es ein Task ist, welcher die lebenserhaltenden Systeme steuert
und überwacht … also ich hätte da schon gerne eine Endlos-Schleife. ;-)
Norbert schrieb:> Nun, wenn es ein Task ist, welcher die lebenserhaltenden Systeme steuert> und überwacht … also ich hätte da schon gerne eine Endlos-Schleife. ;-)
Ich denke auch, dass es eher unschön ist, wenn beim Wiedereintritt die
Raketensteuerung aussetzt, weil sich das Programm beendet hat.
Wilhelm M. schrieb:> Wenn Du in dem Lambda-Ausdruck [](){} die leere Parameterliste weglässt,> wird die durch nichts, auch nichts anderes ersetzt.
Na sicher wird sie das - durch eine leere Parameterliste. Das steht so
im C++-Standard: "If a lambda-expression does not include a
lambda-declarator, it is as if the lambda-declarator were ()."
Also darfst du sie deiner eigenen Logik folgend nie weglassen.
Wilhelm M. schrieb:> Yalu X. schrieb:>> Ich würde übrigens im obigen Lambda-Ausdruck die leere und deswegen>> optionale Parameterliste explizit hinschreiben, weil sonst – ähnlich wie>> bei der weggelassenen Bedingung in for(;;) – überhaupt nicht klar ist,>> was der Compiler dafür einsetzt.>> Leider falsch.> Wenn Du in for(;true;) oder for(;false;) den Boole'schen Wert weglässt,> wird dafür (in C) ein implementation-defined Wert != 0 eingesetzt.>> Wenn Du in dem Lambda-Ausdruck [](){} die leere Parameterliste weglässt,> wird die durch nichts, auch nichts anderes ersetzt.
Nix falsch (Rolf hat dich auf deinen Trugschluss bereits hingewiesen).
Weil dir keine echten Argumente mehr einfallen, begibst dich gerade auf
das Niveau der reinen Wortklauberei. Lass es mich dir noch etwas
ausführlicher erklären, als es Rolf bereits getan hat:
Natürlich hast du insofern recht, dass bei der Spezifikation des
for-Statements im C-Standard das Wort "replaced" auftaucht:
"An omitted expression-2 is replaced by a nonzero constant."
In der Spezifikation der Lambda-Expression im C++-Standard wird der
entsprechende Sachverhalt mit "as if" formuliert:
"If a lambda-expression does not include a lambda-declarator, it is as
if the lambda-declarator were ()."
Da auch beim for-Statement die as-if-Regel gilt, kann der obige Satz
ohne die geringste Änderung seiner Aussage wie folgt umformuliert
werden:
"If a for statement does not include expression-2, it is as if
expression-2 is a nonzero constant."
Uns siehe da, das "replaced", an dem du dich so festkrallst, ist weg,
und die fehlenden expression-2 wird einfach durch nichts ersetzt.
Genauso gut kann der Satz mit dem lambda-declarator ohne die geringste
Änderung seiner Aussage wie folgt formuliert werden:
"An omitted lambda-declarator is replaced by ()."
Jetzt steht auch hier ein "replaced". Die fehlende Parameterliste wird
also durch die leere Parameterliste (ein einfaches Klammerpaar) ersetzt.
Wer also darauf besteht, im Kopf einer Endlosschleife die Bedingung
"true" hinzuschreiben, der sollte konsequenterweise bei parameterlosen
Lambda-Ausdrücken die leere Parameterliste hinschreiben. Wenn du das
partout ablehnst, hat es wenig Sinn, mit dir weiter über Logik in der
Programmierung zu diskutieren.
Yalu X. schrieb:> Wer also darauf besteht, im Kopf einer Endlosschleife die Bedingung> "true" hinzuschreiben,
Ich bestehe nicht darauf und habe nicht darauf bestanden: ich habe nur
gesagt, dass for(;;) weniger explizit als while(true) ist. Und da Rolf
M. nicht weiß, was explizit ist, habe ich geschrieben, dass for(;true;)
explizit ist, nur um ihm und Dir das klar zu machen. Ich habe nicht
darauf bestanden, ein true hinzuschreiben.
> der sollte konsequenterweise bei parameterlosen> Lambda-Ausdrücken die leere Parameterliste hinschreiben.
Nein, beides hat gar nichts miteinander zu tun. Es sind konzeptionell
unterschiedliche Dinge, die dort passieren.
Das eine ist der Ersatz für einen nicht-vorhandenen Ausdruck, und ein
Ausdruck liefert einen Wert. Und das andere ist die Möglichkeit, eine
leere Parameterliste auszudrücken, also kein Ausdruck und damit kein
Wert. Man kann sich nur darüber unterhalten, ob eine leere
Parameterliste (leere Menge) oder eine nicht-vorhandene Parameterliste
(nicht existierende Menge) gleich ist. Da in beiden Fällen kein
Statement des Blocks des L-Ausdrucks etwas der leeren Menge oder der
nicht-existierenden Menge referenzieren kann, ist beides aber
konzeptionell identisch. Es findet auch kein Ersatz durch irgendeinen
Standardwert statt.
> Wenn du das> partout ablehnst,
Ich habe das nicht abgelehnt, auch nicht überall.
Du hast das ins Spiel gebracht.
> hat es wenig Sinn, mit dir weiter über Logik in der> Programmierung zu diskutieren.
Die Texte im C++-Standard sind übrigens (falsch von Dir wiedergegeben,
Du hast C und C++ Standard vermengt):
1
The for statement
2
for ( init-statement conditionopt ; expressionopt ) statement
3
is equivalent to
4
{
5
init-statement
6
while ( condition ) {
7
statement
8
expression ;
9
}
10
}
und
1
Either or both of the condition and the expression can be omitted. A missing condition makes the implied
Wilhelm M. schrieb:> Man kann sich nur darüber unterhalten, ob eine leere Parameterliste> (leere Menge) oder eine nicht-vorhandene Parameterliste (nicht> existierende Menge) gleich ist.
Natürlich sind das zwei verschiedene Dinge, da muss man sich nicht lange
darüber unterhalten. Allerdings wird in Lambda-Ausdrücken eine nicht
vorhandene Parameterliste gleich behandelt wie eine leere. Ebenso wird
eine nicht vorhandene Bedingung in einer for-Anweisung gleich behandelt
wie eine immer erfüllte.
Ob das optionale Ding ein Ausdruck oder eine Parameterliste ist, macht
meiner Meinung nach für Diskussion, die wir hier führen, keinen
Unterschied. Für beide gilt: Entweder man schreibt es explizit hin, oder
man lässt es weg, dann wird es implizit festgelegt.
Wilhelm M. schrieb:> Die Texte im C++-Standard sind übrigens (falsch von Dir wiedergegeben,> Du hast C und C++ Standard vermengt):
Das Thread-Thema ist for(;;) in C:
Jan S. schrieb:> for(;;){} Schleife> Guten Tag,> habe diese Schleife in einer älteren C-Firmware von Pic-Microchip> gesehen
Deswegen habe ich dafür den C-Standard herangezogen.
Die Lambda-Ausdrücke, die du ins Spiel gebracht hast, gibt es aber nur
in C++, deswegen habe ich dort den C++-Standard zitiert.
Ich hätte natürlich auch für for(;;) den C++-Standard zitieren können.
Da sich dort der entsprechende Satz vom C-Standard nur in der
Formulierung, nicht aber in seiner Aussage unterscheidet, hätte dies an
meiner Argumentation nichts geändert.
Roland F. schrieb:> Wilhelm M. schrieb:>> for ( init-statement conditionopt ; expressionopt ) statement>> Da fehlt was.
Falls du das Semikolon meinst: Das ist bereits im init-statement
enthalten.
Wilhelm M. schrieb:> Man kann sich nur darüber unterhalten, ob eine leere> Parameterliste (leere Menge) oder eine nicht-vorhandene Parameterliste> (nicht existierende Menge) gleich ist.
Natürlich sind sie unterschiedlich. Eine Funktion braucht immer eine
Parameterliste. Diese kann leer sein. Im Falle von Lambdas (und nur
dort) hat man eben entschieden, dass sie nicht angegeben werden muss und
dass das exakt so behandelt wird, als hättest du eine leere
Parameterliste angegeben. Genau das sagt doch auch der von mir zitierte
Satz aus dem Standard.
Übrigens würde ich eigentlich erwarten, dass du nicht nur () schreibst,
sondern "explizit" hinschreibst, dass die Parameterliste leer sein soll,
also (void). Wenn du das weglässt, ist sie ja nur noch implizit leer,
und explizit ist doch immer besser als implizit.
> Da in beiden Fällen kein> Statement des Blocks des L-Ausdrucks etwas der leeren Menge oder der> nicht-existierenden Menge referenzieren kann, ist beides aber> konzeptionell identisch. Es findet auch kein Ersatz durch irgendeinen> Standardwert statt.
Der Standardwert ist die leere Liste.
DSGV-Violator schrieb:> Und wenn sich ein Unterprogramm unerwartet beendet, kann es immer noch> von einem Master(-programm) neugestartet werden.
Und was, wenn sich mangels Endlosschleife das Master-Programm beendet
hat?
> Eine unendliche Schleife bedeudet nun mal kontrolleinschränkung/-verlust> für einen Supervisor.
Wenn es um Software im Sinne von manuell gestarteten Programmen geht und
seine Ausführung die Möglichkeit blockiert, andere Programme zu starten,
ja. Auf der anderen Seite stehen µC-Anwendungen, bei denen es essenziell
ist, dass das Programm als Endlosschleife läuft, denn wenn es sich
beenden sollte, passiert je nach dem entweder irgendein Blödsinn, der
Watchdog macht einen Reset des Systems, oder der µC läuft in eine leere
Fallback-Endlosschleife. In der Regel will man keins davon.
Das gleich gilt letztendlich auch für dein Master-Programm /
Betriebssystem.
> Der Standardwert ist die leere Liste.
Liste ist ein Datentyp, aber keine Anweisung/Conbtrol-Struktur. C kennt
im Standard keine Liste, höchstens pointer, bitfields und structs als
komplexere datentypen.
https://de.wikipedia.org/wiki/Liste_(Datenstruktur)
DSGV-Violator schrieb:>> Der Standardwert ist die leere Liste.>> Liste ist ein Datentyp, aber keine Anweisung/Conbtrol-Struktur. C kennt> im Standard keine Liste, höchstens pointer, bitfields und structs als> komplexere datentypen.
Du bist genauso ein Wortklauber wie der Wilhelm. Es dürfte doch aus dem
Kontext mehr als klar hervorgehen, dass mit "Liste" die Parameterliste
gemeint ist.
DSGV-Violator schrieb:> Wilhelm M. schrieb:>> DSGV-Violator schrieb:>>> Naja, das Dumme ist, das Standard-C in der Praxis keine boolean Werte>>> wie 'true' kennt.>>>> Mindestens seit C99 aber schon.>> Nö. Es gibt da schon einen Unterschied zwischen Sprache und> Standardbibliotheken.
Doch. In stdbool.h gibt es bool, ist als der Typ _Bool definiert. Man
kann _Bool natürlich auch direkt verwenden.
Seit C23 sind true, false und bool keywords, das heisst man braucht
stdbool.h und auch _Bool nicht mehr.
bool hat einige interessante Eigenschaften.
1
_Boolb=0;
2
b++;// Ergebnis der Expression ist 0 zurück, enthält nachher 1
3
b++;// Ergebnis der Expression ist 1, b enthält nachher immer noch 1
4
b=10;// b enthält nachher 1
5
b--;// Ergebnis der Expression ist 1, b enthält nachher 0
6
b--;// Ergebnis der Expression ist 0, b enthält nachher 1
7
b--;// Ergebnis der Expression ist 1, b enthält nachher 0
Und ja, auch ein Wert vom typ (_Bool){1} gibt es, also ein echtes true,
das sind nicht simple ints:
DSGV-Violator schrieb:>> Der Standardwert ist die leere Liste.>> Liste ist ein Datentyp, aber keine Anweisung/Conbtrol-Struktur. C kennt> im Standard keine Liste, höchstens pointer, bitfields und structs als> komplexere datentypen.
Es ging nicht um Datentypen, sondern um Parameterlisten. Und die sind
selbstverständlich im C-Standard definiert:
********************************
parameter
formal parameter
formal argument (deprecated)
object declared as part of a function declaration or definition that
acquires a value on entry to the function, or an identifier from the
comma-separated list bounded by the parentheses immediately following
the macro name in a function-like macro definition
********************************
> Wenn es um Software im Sinne von manuell gestarteten Programmen geht und> seine Ausführung die Möglichkeit blockiert, andere Programme zu starten,> ja. Auf der anderen Seite stehen µC-Anwendungen, bei denen es essenziell> ist, dass das Programm als Endlosschleife läuft, denn wenn es sich> beenden sollte, passiert je nach dem entweder irgendein Blödsinn, der> Watchdog macht einen Reset des Systems, oder der µC läuft in eine leere> Fallback-Endlosschleife. In der Regel will man keins davon.
In Sicherheitskritischen Anwendungen wie Space/Avionic will man aber
eine "last resort" Signal-Möglichkeit um das System schnell und mit
definierte Latenz in einem "Safe harbour" Zustand zu bringen. Oder eben
Reboot.
Und natürlich macht nur ein von einem Blödian designtes System
"Blödsinn" nach Beendigung einer Schleife. Ein von einem Kompetenten
Systemdesigner designtes System geht mach programmabarbeitung in einen
definierten Zsutand ("Power-Down, Hibernate, ...). Falls die Mittel der
Software dazu nicht ausreichen muß eben die Hardwareabteilung
entsprechende Abschaltungen (Tri-State, gemeinsames Potential, inert
state) vorsehen.
Aber wie schon das wording "System" hinweist, geht eine solche
Betrachtung weit über den Horizont eines niedrig-hierarchischen
Endlos-C-Schleifen-Programmieres hinaus.
Die NASA hat eben ihren guten Gründe auf in irdischen Massstäben übliche
Programmierweise zu verzichten respektive als bekannt unsicher zu
verbieten.
> Es ging nicht um Datentypen, sondern um Parameterlisten. Und die sind> selbstverständlich im C-Standard definiert:> ********************************> parameter> formal parameter> formal argument (deprecated)> object declared as part of a function declaration or definition that> acquires a value on entry to the function, or an identifier from the> comma-separated list bounded by the parentheses immediately following> the macro name in a function-like macro definition> ********************************
Also das hinter dem 'for' in Klammern heisst jetzt "Parameterliste" wie
bei einem Funktionsaufruf??
Das sind aber nun mal aber im syntax-Sinne keine Parameter sondern
Anweisungen. Deshalb finden sie sich auch im Code- und nicht im
Data-segment.
Jetzt haben die Väter von C explizit eine kurze und konsistente
Endlosschleife realisiert und favorisiert ohne andere Konstrukte
einzuschränken ... und hier wird ernsthaft argumentiert, das nicht zu
nutzen.
Ein Anfänger weiß nicht, dass i++ äquivalent ist zu i=i+1. Der Code wird
aber nicht besser, wenn man auf ++ verzichtet.
Bruno V. schrieb:> und hier wird ernsthaft argumentiert, das nicht zu nutzen.
Ich sehe diese Diskussion auch als nutzlos an. Man kann in C eine
Endlosschleife auf verschiedene Art und Weise produzieren... na und?
Wenn verschiedene Arten angeboten werden, dann kann man die auch nutzen.
Ob die eine oder andere "besser" ist, spielt überhaupt keine Rolle. Der
Compiler erzeugt da ganz emotionslos denselben Code.
Deshalb verstehe ich diesen ganzen Hickhack um Begriffe hier auch nicht.
Der eine oder andere hier mag sich bitte mal besinnen und sich fragen,
ob diese kleinkarierte Diskussion überhaupt der Mühe wert ist.
Bruno V. schrieb:> Jetzt haben die Väter von C explizit eine kurze und konsistente> Endlosschleife realisiert und favorisiert ohne andere Konstrukte> einzuschränken ... und hier wird ernsthaft argumentiert, das nicht zu> nutzen.
Weder konsistent noch favourisiert und "kurz" ist bezüglich der
Forderung nach verständlichen Code auch mehr von Nach- als Vorteil.
Werdet doch endlich mal erwachsen und insestiert nicht, wie es damals
die "Väter" in Ihre Tontafel ritzten, sondern wie es Euch und Eurer Zeit
nutzt. Man läuft doch auch nicht mehr in den gleichen Klamotten wie die
Väter damals ...
Echt, manche haben hier im Forum weniger Selbstbewusstsein, Pragmatismus
und Autonomiestreben als die Aimish oder ein Haufen Schläfenbelockter
Talmud-Schüler. SCNR
https://youtu.be/pc04f4w17rM?t=290https://de.wikipedia.org/wiki/Pragmatismus
Aber eigentlich muss man ja nicht sofort zu einem einstimmigen Fazit
kommen, manchmal genügt es festzustellen, das manche reifer sind als
andere aber noch nicht alles Wasser den Nil abwärts geflossen ist ...
> Wenn verschiedene Arten angeboten werden, dann kann man die auch nutzen.
Eben, goto ist hier das beste Angebot um eine eine unbedingte Schleife
zu schliessen. Aber Goto ist ja böse - hat 'Papa' gesagt.
DSGV-Violator schrieb:> Werdet doch endlich mal erwachsen und fragt nicht wie es damals die> "Väter" in Ihre Tontafel ritzten, sondern wie es Euch und Eurer Zeit> nutzt.
Auch wenn ich Dir in diesem Thread fast nirgends zustimme, so ist das
genau das, was ich hier
Beitrag "Re: for(;;){} Schleife"
schonmal als "katholisch" bezeichnet hatte.
Demnächst wird noch gefordert, dass man doch besser zu den "halben"
Funktionsprototypen im K&R-Stil zurückkehren sollte.
Wilhelm M. schrieb:> Demnächst wird noch gefordert, dass man doch besser zu den "halben"> Funktionsprototypen im K&R-Stil zurückkehren sollte.
Ich fordere die komplette Abkehr von dieser kaputten Sprache.
Das war noch vor meiner Zeit. Es gibt aber durchaus Situationen, in
denen ich die alte Schreibweise noch hätte gebrauchen können, wenn es
sie noch gäbe.
1
// OK:
2
voidmyfunction(intw,inth,intx[h][w]){}
3
4
// Fehler
5
voidmyfunction2(intx[h][w],intw,inth){}
6
7
// Fehler, Schreibweise leider nicht mehr erlaubt:
MaWin O. schrieb:> Ich fordere die komplette Abkehr von dieser kaputten Sprache.
Das kannst du sehr professionell bewerkstelligen:
Stecke einfach den Kopf in den Sand.
Es gibt ja auch ›gute‹ Programmiersprachen für den Vogel Strauß,
›Scratch‹ fiele mir da ein, oder ›Turtle-Graphics‹
DSGV-Violator schrieb:> Also das hinter dem 'for' in Klammern heisst jetzt "Parameterliste" wie> bei einem Funktionsaufruf??
Nein, wie kommst du denn darauf?
> Das sind aber nun mal aber im syntax-Sinne keine Parameter sondern> Anweisungen. Deshalb finden sie sich auch im Code- und nicht im> Data-segment.
In C gibt es kein Code- oder Data-Segment. Abgesehen davon hat das auch
rein gar nichts mit Parameterlisten zu tun.
DSGV-Violator schrieb:> Werdet doch endlich mal erwachsen und insestiert nicht, wie es damals> die "Väter" in Ihre Tontafel ritzten, sondern wie es Euch und Eurer Zeit> nutzt. Man läuft doch auch nicht mehr in den gleichen Klamotten wie die> Väter damals ...
Ich habe das nicht nach den "Vätern" gemacht. Ich wusste nicht einmal,
dass das im K&R so steht, bevor es hier jemand zitiert hat. Ich habe
selbst für mich entschieden, dass ich diese Form für Endlosschleifen
bevorzuge, und zwar primär, weil ich die eigentlich unnütze Bedingung
nicht angeben muss. Das macht es für mich einfach zur natürlicheren Wahl
für eine unbedingte Schleife. Ich war dann aber doch sehr erstaunt, als
Wilhelm das als "an den Haaren herbeigezogen" betitelt hat.
>> Wenn verschiedene Arten angeboten werden, dann kann man die auch nutzen.>> Eben, goto ist hier das beste Angebot um eine eine unbedingte Schleife> zu schliessen. Aber Goto ist ja böse - hat 'Papa' gesagt.
Für Endlosschleifen ist es auch nicht wirklich sinnvoll. Es gibt aber
sinnvolle Anwendungsfälle von goto, und dort verwende ich es dann auch.
> In C gibt es kein Code- oder Data-Segment. Abgesehen davon, hat das auch> rein gar nichts mit Parameterlisten zu tun.
Doch hat es, Parameter sind Daten und Zuweisungen sind Instruktionen.
> Ich habe> selbst für mich entschieden, dass ich diese Form für Endlosschleifen> bevorzuge,
Neee wie Du das für Dich entscheidest interessiert kein Schwein und kein
Compiler. Du hast hier garnichts "selbst" zu entscheiden, du hast (wie
jeder andere auch) korrekten und möglichst verständlichen Syntax zu
schreiben. Und für viele ist eben eine Ausage wie etwas nicht ist (Eine
unendliche Schleife ist wie eine Schleife ohne Parametreliste) nicht
sonderlich erklärend.
Im Hitchhiker und anderer Belletristik finden sich solche
Gedankenmuster, die etwas über ihre Nicht-Sein erklären wollen, bspw.:
"Fliegen heißt Lernen sich auf den Boden zu schmeißen und ihn zu
verfehlen. Flying is learning how to throw yourself at the ground and
miss."
> Für Endlosschleifen ist es auch nicht wirklich sinnvoll.
Doch gerade bei Endloschleifen ist das sinnvoll. Weil ja der Sinn (und
das Compilat) hinter einer "Endlosschleife" der unbedingte Sprung ist.
Und welches Schlüsselwort hat C für "unbedingten Sprung" vorgesehen?
Eben, "Goto" .
DSGV-Violator schrieb:>> In C gibt es kein Code- oder Data-Segment. Abgesehen davon, hat das auch>> rein gar nichts mit Parameterlisten zu tun.>> Doch hat es, Parameter sind Daten und Zuweisungen sind Instruktionen.
Parameter landen aber in der Regel in Registern oder auf dem Stack, und
das true in der Schleifenbedingung ist keine Zuweisung, sondern ein
Ausdruck, der vom Compiler üblicherweise komplett wegoptimiert wird,
also nachher meist gar nirgends landet. Das ist aber alles wie gesagt in
C nicht spezifiziert, sondern komplett vom Compiler abhängig und damit
in diesem Zusammenhang irrelevant.
>> Ich habe>> selbst für mich entschieden, dass ich diese Form für Endlosschleifen>> bevorzuge,>> Neee wie Du das für Dich entscheidest interessiert kein Schwein und kein> Compiler.
Dass es dem Compiler egal ist, haben wir vor langem bereits
festgestellt. Und ob es ein "Schwein" interessiert ist mir egal, denn
für die schreibe ich den Code nicht. Ich schreibe ihn abgesehen vom
Compiler für Programmierer, die der Sprache zumindest auf einem gewissen
Grundniveau mächtig sind. Wer nicht mal weiß, wie eine for-Schleife
funktioniert, soll lieber die Finger davon lassen, bis er es gelernt
hat.
> Du hast hier garnichts "selbst" zu entscheiden, du hast (wie> jeder andere auch) korrekten und möglichst verständlichen Syntax zu> schreiben.
Ich kann sehr wohl entscheiden, wie ich meinen Code schreibe, denn du
bist nicht die Codepolizei, die mir das verbieten könnte. Und ja, ich
habe mich dazu entschieden ihn korrekt und möglichst verständlich zu
schreiben.
for (;;) ist weder inkorrekt, noch unverständlich.
> Und für viele ist eben eine Ausage wie etwas nicht ist (Eine> unendliche Schleife ist wie eine Schleife ohne Parametreliste) nicht> sonderlich erklärend.
Das ist wie bei den meisten Stilfragen und wie auch hier schon öfter
angemerkt wurde, etwas subjektives. Ich finde es klar, lesbar und
einleuchtend. Das magst du anders sehen, aber das ist dann eben deine
persönliche Sichtweise, sprich: Du hast für dich entschieden, dass du
eine andere Schreibweise bevorzugst - oder jemand anders hat das für
dich entschieden, und du folgst dem nur dogmatisch. Mehr Optionen gibt's
da nicht.
>> Für Endlosschleifen ist es auch nicht wirklich sinnvoll.> Doch gerade bei Endloschleifen ist das sinnvoll. Weil ja der Sinn (und> das Compilat) hinter einer "Endlosschleife" der unbedingte Sprung ist.> Und welches Schlüsselwort hat C für "unbedingten Sprung" vorgesehen?> Eben, "Goto" .
Mit der Argumentation kannst du alle Schleifen per goto umsetzen, denn
mit einem if kannst du dem ja auch eine Bedingung hinzufügen.
Aber eine Schleife wird in C nunmal üblicherweise mit for oder
(do/)while und einem Codeblock geschrieben. Warum sollte ich davon bei
einer Endlosschleife abweichen? Das wäre tatsächlich unintuitiv. Ich
würde aus Gründen der Lesbarkeit generell davon abraten, goto für
Rückwärtssprünge zu verwenden.
(prx) A. K. schrieb:> Bemerkenswert, wie man sich derart ernst und so lange mit einem derart> lächerlichen Thema befassen kann.
Wie so oft in diesem Forum wurde auch in diesem Thread die Frage des TE
schon nach kurzer Zeit korrekt beantwortet, worauf sich eine Diskussion
über angrenzende Themen anschloss, die für einige interessant sein
mögen, für andere nicht.
Wer den Thread nur deswegen öffnet, weil er dasselbe Problem wie der TE
hat und ausschließlich an der Antwort auf die Ursprungsfrage
interessiert ist, kann den Thread schon nach wenigen Minuten wieder
verlassen. Wer an einer weiterführenden Diskussion interessiert ist,
bleibt drin. So kommt letztendlich jeder auf seine Kosten.
In diesem Forum herrscht diesbezüglich eine andere Kultur als bspw. auf
stackoverflow.com, mikrocontroller.net hat aber IMHO auch weder das Ziel
noch die Ressourcen, ein deutschsprachiges stackoverflow.com zu werden.
Dass solche freien Diskussionen auf mikrocontroller.net oft ergebnislos
verlaufen, sollte jedem klar sein, der daran teilnimmt. Ob eine
Diskussion trotz absehbarer Ergebnislosigkeit wenigstens einen
Erkenntnisgewinn liefern kann, muss jeder für sich selbst entscheiden.
Ich persönlich finde die Diskussion hier trotz ihrer Bedeutungslosigkeit
für die Praxis eigentlich recht interessant. Auf der anderen Seite gibt
es hier Threads mit über hundert Teilnehmern und mehreren Tausend
Beiträgen, die für mich völlig irrelevant sind, deren Teilnehmerzahl
aber auf ein großes Interesse bei anderen Leuten schließen lässt. Auch
diese Threads sind für mich völlig in Ordnung, ich schaue dann eben nur
selten oder überhaupt hinein.
Rolf M. schrieb:> for (;;) ist weder inkorrekt, noch unverständlich.
Es ist unverständlich. "Für nichts" ist kein intuitiver Begriff für eine
Endlosschleife.
MaWin O. schrieb:> Rolf M. schrieb:>> for (;;) ist weder inkorrekt, noch unverständlich.>> Es ist unverständlich. "Für nichts" ist kein intuitiver Begriff für eine> Endlosschleife.
Und "Während eins" ist besser?
> Dass es dem Compiler egal ist, haben wir vor langem bereits> festgestellt. Und ob es ein "Schwein" interessiert ist mir egal, denn> für die schreibe ich den Code nicht. Ich schreibe ihn abgesehen vom> Compiler für Programmierer, die der Sprache zumindest auf einem gewissen> Grundniveau mächtig sind. Wer nicht mal weiß, wie eine for-Schleife> funktioniert, soll lieber die Finger davon lassen, bis er es gelernt> hat.
Um aber eine Endlosschleife zu realisieren braucht man keinerlei
Kenntnisse bzgl des for-Konstruktes. Das zu (;;) verstümmelte
for-konstrukt funktioniert nur, weil extra noch ein paar Sonder-Regel
eingeführt worden, um den Parser/Compiler das "Kotzen" bei diese
unlogischen Notation auszutreiben.
>> Du hast hier garnichts "selbst" zu entscheiden, du hast (wie>> jeder andere auch) korrekten und möglichst verständlichen Syntax zu>> schreiben.>> Ich kann sehr wohl entscheiden, wie ich meinen Code schreibe, denn du> bist nicht die Codepolizei, die mir das verbieten könnte. Und ja, ich> habe mich dazu entschieden ihn korrekt und möglichst verständlich zu> schreiben.> for (;;) ist weder inkorrekt, noch unverständlich.
Träum weiter, träum tief - bin ich hier im falschen Film?
Da fragt ein TO weil ihm das Konstrukt unbekannt und unverständlich ist.
Und dann kommt so ein selbstgefälliges Irgendwas daher und behauptet
ungeniert "Das ist ist nicht unverständlich, das ist verständlich."
Dann kann man nur noch "Kognitive Dissonanz" diagnostizieren:
https://www.bfi-ooe.at/de/blog/warum-wir-uns-selbst-austricksen-ohne-es-zu-merken-kognitive-dissonanz.html
"Verschlimmbesserung" ist auch eine Kulturtechnik, um sich nicht selbst
die Sinnlosigkeit seiner Existenz eingestehen zu müßen.
> Das ist wie bei den meisten Stilfragen und wie auch hier schon öfter> angemerkt wurde, etwas subjektives. Ich finde es klar, lesbar und> einleuchtend. Das magst du anders sehen, aber das ist dann eben deine> persönliche Sichtweise, sprich: Du hast für dich entschieden, dass du> eine andere Schreibweise bevorzugst
Nein, das ist keine Frage des sprachlichen Stils, sondern die nach der
Konstruktion eines mathematischen Formelapperates zur Realisation von
Algorithmenmaschinen. Eben wie die Turing-maschine. Das "Weglassen" gibt
es im Mathematischen Sinne nicht, da gibt es nur ein neutrales Element
um eben eine bijektive Abbildung zwischen symbol und Instruktion-Code zu
ermöglichen. Ja, ich weiß, die mathematischen Grundlagen interessieren
einen 0815 Codierschwein wenig.
https://www.cs.virginia.edu/~robins/Turing_Paper_1936.pdf> Mit der Argumentation kannst du alle Schleifen per goto umsetzen,
Das ist aber keine Argumentation bezüglich aller Schleifen sondern nur
um den Spezialfall einer degenerierten, da alle wesentlichen
Schleifeneigenschaften (Anfangsbedingung, Iterationsanweisung,
Anfangsbedingung) fehlen respektive nicht gebraucht werden.
Eine " for index in anfangswert bis Endwert-schleife ist also völlig
"überdimensioniert". Es ist halt so, also ob man zum Brötchenholen um
die Ecke extra den VW-Bully aus der Garage holt statt den kurzen Gang
direkt zu erledigen.
Man lernt dann, ok, Initialisierung, Bedingung, und was für nach dem
Durchlauf.
Dass man das erste und letzte leer lassen kann, ist nicht so
erstaunlich. Es gibt ja auch leere Statements (einfach nur ";"), und
Parameterlisten von Funktionen kann man auch leer lassen.
Aber an einem Ort, wo man den Wert eines Ausdrucks braucht, den
weglassen zu können, wie kommt man dort darauf, das man das kann? Egal
ob in Zuweisungen, Initialisierungen, Operanden, if Bedingungen, while
schleifen, Funktionsaufrufen, etc, dort kann man das sonst nie machen.
Die ersten paar Jahre wusste ich nicht, dass man die Bedingungen
weglassen kann. Es ist nicht logisch. Es ist überraschend, unerwartet,
ein Spezialfall, den man einfach kennen muss!
Darum ist meine lieblingsendlosschleife immer noch "while(true)"
MaWin O. schrieb:> Rolf M. schrieb:>> for (;;) ist weder inkorrekt, noch unverständlich.>> Es ist unverständlich. "Für nichts" ist kein intuitiver Begriff für eine> Endlosschleife.
So zu argumentieren, bringt nichts, denn
Yalu X. schrieb:> Wer versucht, Programmcode zu verstehen, indem er ihn ins Deutsche> übersetzt, hat schon von vornherein verloren.MaWin O. schrieb:> Deshalb schreibt man ja auch "Während wahr". Bzw "Solange wahr".
Sagst du das auch im normalen Sprachgebrauch so?
Auf was bezieht sich dieses "wahr" bzw. was genau muss wahr sein, damit
die Schleife weiterläuft?
jetzt schütte ich mal mehr Öl ins Feuer um etwas Perspektive zu
präsentieren;-)
Früher(TM) genügte es bei kommerziellen Programmier Werkzeugen die
zugehörigen mitgelieferten Handbücher zu studieren und erfuhr genug
Information um damit in C arbeiten zu können. (KEIL z.B.) Es war in den
meisten Fällen NICHT notwendig andauernd die Compiler Standards und
andere "highvoluting" akademischen Unterlagen zu recherchieren. Die
damaligen Compiler waren auch viel einfacher wie C++ und Abkömmliche.
Ohne grosse Theorie und langjähriges UNI-Studium konnte also der
"Gelegenheitsprogrammierer" seine Projekte mit den (gedruckten)
Unterlagen durchziehen, weil genug Information vorhanden waren. Und ja,
Internet war damals für die meisten noch nicht zugänglich.
Kostenpflichtige offizielle Dokumente waren ohnehin für die meisten
nicht erschwinglich.
Wenn also damals dann die Compiler Doku konstatierte, dass eine
parameterloses for(;;) wie beschrieben funktionieren soll, dann dachte
man nicht mehr weiter daran und hielt sich an die Documentation um
funktionierende Programme schreiben zu können. So einfach war das damals
und man war effektiv im Job um sein Problem zeitgemaess lösen zu können.
Viele damals waren keine Computer Science Akademiker für die
"Programmieren" eben hin und wieder nur notwendig war, um ein Problem
lösen zu können und keine hochgradige Wissenschaft die nur sich selber
zum Ziel hatte. Viele mußten sich die Computer Programmiersprachen
selbst beibringen. Die Werkzeuge waren da um deren anfallende Probleme
lösen zu können. Im Vergleich zu C sind die esoterischen Funktionen von
C++ ohne ausführliches Studium der Compiler Referenzliteratur
unleserlich bzw. unverständlich für den nicht-Praktiker. Ein typisches C
Programm dagegen, war zumindest nach Lesen von K&R und Werkzeug
Dokumention, wenn gut geschrieben, meistens vollkommen verständlich.
Das sollte man heute zum Vergleich nicht vergessen. Die heutige Welt mit
ihren modernen Sprachen-Produkten wie Java, PHP, Python, Rust, etz.
spielt in einer total anderen Liga. Die heutigen Programme zeigen
heutzutage aber oft ein hochgradiges Mass an Sprachen Esoterik und
Abstraktion, das ohne weiteres Studium nicht mehr ohne Weiteres
verständlich ist. Ob das wirklich notwendig ist, kann ich nicht
beurteilen. Aus der Sicht eines Akademikers ist das obige natuerlich
alles Blasphemie. Aber man sollte berücksichtigen, dass viele Menschen
sich damit nur so weit befassen wollen, weil sie ein Problem zu lösen
haben.
Ist nur meine Meinung.
Yalu X. schrieb:> Sagst du das auch im normalen Sprachgebrauch so?
Welche Relevanz hat das für eine Programmiersprache?
> Auf was bezieht sich dieses "wahr" bzw.
Auf nichts. Steht doch da. Sonst hieße es "Solange X wahr".
> was genau muss wahr sein, damit> die Schleife weiterläuft?
Wahr muss wahr sein.
Gerhard O. schrieb:> Aber man sollte berücksichtigen, dass viele Menschen> sich damit nur so weit befassen wollen, weil sie ein Problem zu lösen> haben.
Einer der Hauptgründe dafür, dass so viel Software so ein Sondermüll
ist.
Gerhard O. schrieb:> um etwas Perspektive zu> präsentieren;-)
Da gibt es mit Folge 13 aus Season 2 von "BigBangTheory" auch ein
Beispiel aus der Populärkultur zum korrekten Umgang/Notation mit/von
Endlosschleifen.
https://youtu.be/7dz-7T9HYic?t=45
Bei Sheldons Freundschaftsalgorithmus scheint eine Endlosschleife
jegliche soziale Anstrengung ad absurdum zu führen, bis "der Ingenieur
im Team" das Verfahren mit einem Schleifenzähler, Abbruchbedingung zur
LOA ( am wenigsten unangenehm - "Least Objectionable Activity")
entschärft bzw. zu einem Abschluss bringt.
Im Anhang Programmablaufplan mit endlosschleife und debuggt
Man sieht, ohne Abbruchbedingung funktioniert die Show nicht. SCNR ;-)
https://www.myfanbase.de/the-big-bang-theory/episodenguide/?eid=4367
DSGV-Violator schrieb:> Das zu (;;) verstümmelte for-konstrukt funktioniert nur, weil extra noch> ein paar Sonder-Regel eingeführt worden, um den Parser/Compiler das> "Kotzen" bei diese unlogischen Notation auszutreiben.
Das ist eine sehr unglückliche Formulierung. Besser: Die Option, eine
Bedingung wegzulassen ist genau dafür eingeführt worden, um damit
Schleifen formulieren zu können, für die man keine Bedingung möchte.
> Träum weiter, träum tief - bin ich hier im falschen Film?> Da fragt ein TO weil ihm das Konstrukt unbekannt und unverständlich ist.
Und wenn morgen einer fragt, was denn das komische * nach dem Typ ist,
dann benutzt du nie mehr Pointer, weil die unverständlich sind? So ein
Forum ist nunmal auch dafür gedacht, dass Leute Fragen stellen, weil sie
noch nicht alle Grundlagen kennen. Aus einer einzelnen Frage lässt sich
nicht schließen, dass etwas unverständlich ist. Hab ich aber oben
eigentlich schon mal erwähnt.
Ich bin mir auch ziemlich sicher, dass er es nach der ersten Antwort
gleich verstanden hat und jetzt für den Rest seines Lebens weiß.
[Beleidigungen entfernt…]
> Nein, das ist keine Frage des sprachlichen Stils,
Na sicher. Die Sprache bietet verschiedene syntaktisch korrekte
Möglichkeiten, eine Endlosschleife zu formulieren. Semantisch können sie
als äquivalent angesehen werden, weil das Verhalten des Programms in
allen Varianten das gleiche sein wird. Welche davon man verwendet, ist
also selbstverständlich eine Frage des sprachlichen Stils und nichts
anderes.
>> Mit der Argumentation kannst du alle Schleifen per goto umsetzen,>> Das ist aber keine Argumentation bezüglich aller Schleifen sondern nur> um den Spezialfall einer degenerierten, da alle wesentlichen> Schleifeneigenschaften (Anfangsbedingung, Iterationsanweisung,> Anfangsbedingung) fehlen respektive nicht gebraucht werden.
Die grundlegende Eigenschaft einer Schleife ist die Wiederholung. Der
Rest sind optionale Zusätze, die man manchmal, aber nicht immer braucht.
> Eine " for index in anfangswert bis Endwert-schleife ist also völlig> "überdimensioniert".
Genau deswegen kann man die drei in diesem Fall überflüssigen Ausdrücke
ja weglassen, statt sowas wie for(true; true; true) oder derlei
hinschreiben zu müssen.
MaWin O. schrieb:>> was genau muss wahr sein, damit>> die Schleife weiterläuft?>> Wahr muss wahr sein.
Und du findest es umgangssprachlich ganz normal, wenn man sagt, dass man
etwas so lange tut, wie wahr wahr ist?
> [Beleidigungen entfernt…]
Nein, da stehen keinen Beleidigungen und da wurde auch nichts
entfernt...
Das mit der kognitiven Dissonanz, also "Tatsache A" sehen und "Story B"
erzählen oder die im Link beschriebene Verhaltensweise "Warum wir uns
selbst austricksen ohne es zu merken" zeigst Du ziemlich oft im thread.
;-) SCNR
MaWin O. schrieb:> Yalu X. schrieb:>> Sagst du das auch im normalen Sprachgebrauch so?>> Welche Relevanz hat das für eine Programmiersprache?
Keine. Aber warum schreibst du dann:
MaWin O. schrieb:> Rolf M. schrieb:>> for (;;) ist weder inkorrekt, noch unverständlich.>> Es ist unverständlich. "Für nichts" ist kein intuitiver Begriff für eine> Endlosschleife.
Für mich ist "solange wahr" genauso intuitiv oder unintuitiv wie
"für nichts", weil beides kein korrektes Deutsch ist.
MaWin O. schrieb:>> Auf was bezieht sich dieses "wahr" bzw.>> Auf nichts. Steht doch da. Sonst hieße es "Solange X wahr".
Hmm, seltsam. Ich dachte immer, dass sich ein Adjektiv auf ein
Substantiv beziehen muss.
>> was genau muss wahr sein, damit>> die Schleife weiterläuft?>> Wahr muss wahr sein.
Ach so. Wie sieht es dann aus mit while(false)?
Nach deiner Argumentation muss dann falsch falsch sein, damit die
Schleife weiterläuft. Ich würde mal behaupten, dass falsch immer falsch
ist, also könnte nach deiner Argumentation eine Endlosschleife auch mit
while(false) eingeleitet werden.
Was lernen wir daraus?
Man sollte sich bei der Programmierung nie auf die Intuition verlassen.
Für eine Programmiersprache gibt es (im Gegensatz zu natürlichen
Sprachen) eine umfassende Spezifikation sowohl der Syntax als auch der
Semantik, da ist Intuition weder notwendig noch zielführend.
Ich kann deswegen nur wiederholen, was hier schon oft geschrieben wurde:
Wenn ihr ordentlich programmieren wollt, dann besorgt euch ein Buch zur
betreffenden Programmiersprache und arbeitet es von der ersten bis zur
letzten Seite durch. Dann bedarf es keiner fraglichen Hilfsmittel wie
Intuition oder die Übersetzung von Programmkonstrukten in natürliche
Sprache.
Wenn ihr dann Code von anderen vorgesetzt bekommt, ist es völlig
unerheblich, ob dort Endlosschleifen mit for(;;), while(1), while(true)
oder goto formuliert sind, weil ihr alle 4 Varianten versteht.
Rolf M. schrieb:> Und du findest es umgangssprachlich ganz normal, wenn man sagt, dass man> etwas so lange tut, wie wahr wahr ist?
Wo habe ich das gesagt?
Yalu X. schrieb:> Für mich ist "solange wahr" genauso intuitiv oder unintuitiv wie> "für nichts", weil beides kein korrektes Deutsch ist.
Dann kann man die Endlosschleife ja auch quibbelbobbel nennen. Das ist
nach deiner Logik dann ja genau so gut wie for(;;)
1
quibbelbobbel{
2
...
3
}
Yalu X. schrieb:>> Wahr muss wahr sein.>> Ach so. Wie sieht es dann aus mit while(false)?
bricht sofort ab, weil false ganz offensichtlich false ist und nie true
werden kann.
> Nach deiner Argumentation muss dann falsch falsch sein, damit die> Schleife weiterläuft.
Hä? Nein. Unsinn.
Yalu X. schrieb:> Dann bedarf es keiner fraglichen Hilfsmittel wie> Intuition oder die Übersetzung von Programmkonstrukten in natürliche> Sprache.
Warum sind die C-Schlüsselwörter dann in Englisch, wenn das doch
schlecht ist und man stattdessen lieber alles aus einem Buch von Grund
auf lernen soll?
Man könnte 'if' ja falschverstehen. Lieber 'quappelsack' verwenden.
> Wenn ihr dann Code von anderen vorgesetzt bekommt, ist es völlig> unerheblich, ob dort Endlosschleifen mit for(;;), while(1), while(true)> oder goto formuliert sind, weil ihr alle 4 Varianten versteht.
Naja, aber verpflichtende Code-Stile wurden doch gerade eingeführt, weil
eben nicht davon auszugehen ist, das jeder im Team jede syntaktische
Sonderlocke beherrscht.
Hinzukommt bei Sicherheitsrelevanter Soft wie für Avionik oder
Medizintechnik, das man die Compiler in ihrer benutzten Version
zertifizieren muß, also sicherstellen, das bei den benutzten
Syntax-Gekröse immer das selbe raus kommt. Damit diese Testerei nicht
ausartet, schränkt man eben die benutzten varianten ein. Also eben
Projektweit eine Variante eine Schleife zu implementieren und nicht alle
88 Möglichen. Gern wird auch die Richtung und eine Grenze der Iteration
vorgegeben, bspw. Down to 0. Das macht auch dem Tester das Leben beim
Schreiben der corner cases einfacher.
Also eben KISS Prinzip, auch bei der AusWahl der synonymen
Source-Code-Optionen.
https://en.wikipedia.org/wiki/Programming_style
PS:
Natürlich kann man sich auch vom nerdigen Spass beim Progrrammieren
leiten lassen. Das führte wohl zu der Vermutung, das Dennis Ritchie und
Brian Kernighan "C" als Scherz ("Hoax")/Persiflage zu Pascal andachten
und nie als ernsthaftes Programmiersprache sahen. Sie sollen sich auch
angeblich entschuldigt haben. ;-)
https://www.cs.cmu.edu/~jbruce/humor/unix_hoax.html
Zitat:
"We stopped when we got a clean compile on the following syntax:
MaWin O. schrieb:> Einer der Hauptgründe dafür, daß so viel Software so ein Sondermüll> ist.
Es ist aber andrerseits durchaus vorstellbar, daß auch Computer Science
Nichtakademiker klare und logisch fundierte Praxis Programme erdenken
können die im Kontext ihrer Tätigkeiten täglich benötigt werden und die
Doku der eingesetzten Sprache verstanden worden ist.
Auch ist es vorstellbar, daß unzählige Elektronik Ingenieure in der
Vergangenheit und Gegenwart funktionell erstklassige Produkte mit den in
der Uni absolvierten Kursen programmieren können. In Fakt, es ist sogar
vorstellbar, daß viele embedded Produkte der Vergangenheit deswegen
einwandfrei und zügiger funktionierten und keine Cloudanbindung zu
häufigen SW Upgrades benötigten.
Böswillige Zungen behaupten auch heute noch, daß embedded Geräte der
Vergangenheit oft sogar besser funktionierten als viele der
überzüchteten Sachen der Gegenwart die ohne Anbindung ans Mutterschiff
und deren fragilen Wolkenbänken nicht mehr richtig oder überhaupt
funktionieren und ewig zum Neu-Booten brauchen.
Leider sterben die Leute aus, die es besser erlebt haben und man kann
nicht mehr vergleichen, weil die User der Gegenwart es nicht besser
erlebt haben.
Ein VCR oder CD-Abspielgerät funktionierte praktisch sofort, während
sich das DVD Abspielgerät minutenlang plagt um überhaupt
verwendungsfähig zu werden. Vielleicht gibt es dazu gute Gründe, wer
weiß, nur versäumen es die Hersteller es zu erklären warum so vieles
Zeugs lahme Enten sind.
Aber was weiß ich, Fossil der Vergangenheit. der vergleichen kann?
MaWin O. schrieb:> Rolf M. schrieb:>> Und du findest es umgangssprachlich ganz normal, wenn man sagt, dass man>> etwas so lange tut, wie wahr wahr ist?>> Wo habe ich das gesagt?
Es ergibt sich aus dem von dir geschriebenen. Du meintest, "solange
wahr" sei intuitiv, und auf die Frage, was denn überhaupt wahr sein
müsse, weil der Satz unvollständig ist, meintest du:
MaWin O. schrieb:> Wahr muss wahr sein.MaWin O. schrieb:> Yalu X. schrieb:>> Für mich ist "solange wahr" genauso intuitiv oder unintuitiv wie>> "für nichts", weil beides kein korrektes Deutsch ist.>> Dann kann man die Endlosschleife ja auch quibbelbobbel nennen. Das ist> nach deiner Logik dann ja genau so gut wie for(;;)
Nur wenn man meint, es müsse unbedingt 1:1 auf gesprochene Sprache
abbildbar sein. Das scheinst aber nur du so zu sehen. Aber das passt ja
auch schon für klassische Zählschleifen nicht:
1
for(inti=0;i<10;++i)
Wenn man die einfach 1:1 in gesprochene Sprache übersetzt, kommt in etwa
sowas raus: "Für erzeuge neuen integer i und initialisiere ihn mit Wert
0, ist i kleiner als 10? und inkrementiere i."
Das ergibt sprachlich auch nicht viel mehr Sinn. Deiner Argumentation
nach müsste man dann also for-Schleifen generell komplett umbauen, weil
sie sonst nicht intuitiv sind.
Gerhard O. schrieb:> Leider sterben die Leute aus, die es besser erlebt haben
Ja? Software war früher besser?
Ich muss dich enttäuschen. Das ist die typische früher-war-alles-besser
Verzerrung.
Software war früher noch viel beschissener als heute. Aber das heißt
nicht, dass Software heute gut ist.
Glaubst du nicht? Dann installiere doch nochmal MS-DOS auf einem alten
Rechner.
Oder Windows 95. Oder spiele nochmal ein Spiel auf einem C64.
Das ist aus heutiger Sicht gesehen sowohl von der UX als auch von der
Softwarequalität absoluter nuklearer Kernschrott.
Die "gute alte Zeit" gibt es bei Software nicht.
Auch nicht im Embedded-Bereich. Schonmal ein Golf-3-Steuergerät
ausgelesen?
Oder jedes beliebige andere Gerät mit Firmware drauf aus den 90ern.
Absoluter Schrott war das aus heutiger Sicht.
Rolf M. schrieb:>> Wo habe ich das gesagt?>> Es ergibt sich aus dem von dir geschriebenen. Du meintest, "solange> wahr" sei intuitiv, und auf die Frage, was denn überhaupt wahr sein> müsse, weil der Satz unvollständig ist,
Aha. Danke für die Bestätigung, dass ich das gar nicht gesagt habe.
Rolf M. schrieb:> "Für erzeuge neuen integer i und initialisiere ihn mit Wert> 0, ist i kleiner als 10? und inkrementiere i."
Nur, wenn man mit dem Klammerbeutel gepudert wurde.
Normale Menschen lesen das als 'for i from 0 to one less than 10'.
Rolf M. schrieb:> Deiner Argumentation> nach müsste man dann also for-Schleifen generell komplett umbauen, weil> sie sonst nicht intuitiv sind.
Das ist in der Tat wahr.
Die C-for-Schleife ist einfach nur veralteter Schrott.
Heute macht man das mit Iteratoren viel intuitiver, lesbarer und
sicherer.
Die Schrottsprache C beherrscht das aber natürlich nicht.
MaWin O. schrieb:> Yalu X. schrieb:>> Für mich ist "solange wahr" genauso intuitiv oder unintuitiv wie>> "für nichts", weil beides kein korrektes Deutsch ist.>> Dann kann man die Endlosschleife ja auch quibbelbobbel nennen. Das ist> nach deiner Logik dann ja genau so gut wie for(;;)
Nein, meine Argumentation beschränkte sich auf while(true) und for(;;).
MaWin O. schrieb:>> Nach deiner Argumentation muss dann falsch falsch sein, damit die>> Schleife weiterläuft.>> Hä? Nein. Unsinn.
Möglicherweise habe ich deine Aussage
MaWin O. schrieb:> Wahr muss wahr sein.
falsch interpretiert. Macht aber nichts, weil das Problem mit der Logik
schon vorher begann weder von dir noch von mir aufgelöst werden konnte:
Yalu X. schrieb:> MaWin O. schrieb:>>> Auf was bezieht sich dieses "wahr" bzw.>>>> Auf nichts. Steht doch da. Sonst hieße es "Solange X wahr".>> Hmm, seltsam. Ich dachte immer, dass sich ein Adjektiv auf ein> Substantiv beziehen muss.MaWin O. schrieb:> Warum sind die C-Schlüsselwörter dann in Englisch, wenn das doch> schlecht ist und man stattdessen lieber alles aus einem Buch von Grund> auf lernen soll?
Damit man sie sich besser merken kann, nachdem man einmal ihre
Definition gelsen hat. So etwas nennt man auch Gedächtnisstütze (engl.
Mnemonic) und hat mit Intuition wenig bis gar nichts zu tun.
Yalu X. schrieb:> Damit man sie sich besser merken kann, nachdem man einmal ihre> Definition gelsen hat. So etwas nennt man auch Gedächtnisstütze (engl.> Mnemonic) und hat mit Intuition wenig bis gar nichts zu tun.
Achso.
1
bang (x == 1) {
2
shoot;
3
}
Man muss nur lernen, dass 'bang' eine Bedingungsabfrage ist und 'shoot'
der Funktionsabbruch.
Intuition ist ja was böses, deshalb sind diese Keywords besser als 'if'
und 'return'. Die könnte ja jemand falsch verstehen.
MaWin O. schrieb:> Aha. Danke für die Bestätigung, dass ich das gar nicht gesagt habe.
Dann hast du dich wohl nur ungeschickt ausgedrückt, denn so kam es
rüber.
> Rolf M. schrieb:>> "Für erzeuge neuen integer i und initialisiere ihn mit Wert>> 0, ist i kleiner als 10? und inkrementiere i.">> Nur, wenn man mit dem Klammerbeutel gepudert wurde.> Normale Menschen lesen das als 'for i from 0 to one less than 10'.
Ach komm, jetzt machst du dich lächerlich. Erst sprichst du von "für
nichts" und sagst, das sei doch so unintuitiv, weil du es wörtlich
nimmst, und jetzt sagst du bei einem anderen Beispiel, dass man das doch
nur anders lesen muss. Und bei diesem gebe ich dir auch recht.
> Die C-for-Schleife ist einfach nur veralteter Schrott.> Heute macht man das mit Iteratoren viel intuitiver, lesbarer und> sicherer.
Die einzige Sprache, die ich kenne, die Zählschleifen mit Iteratoren
macht, ist Python. Damit könnte man sicherlich auch Endlosschleifen
machen, aber das wäre dann doch eher ungewöhnlich.
Rolf M. schrieb:> das sei doch so unintuitiv, weil du es wörtlich nimmst
Wie nimmt man 'nichts' denn unwörtlich?
Wenn man 'nichts' als 'ever' interpretieren kann, dann auch als 'never'.
Eine Zählschleife, bei der Werte angegeben sind (also mehr als nichts),
kann man hingegen nicht ohne diese Werte interpretieren. Nichts kann man
als alles interpretieren. Das ist der Unterschied.
Rolf M. schrieb:> Die einzige Sprache, die ich kenne, die Zählschleifen mit Iteratoren> macht, ist Python. Damit könnte man sicherlich auch Endlosschleifen> machen, aber das wäre dann doch eher ungewöhnlich.
Ganz im Gegenteil. Endlose Generatoren sind ziemlich üblich. Auch in
Python.
Yalu X. schrieb:> Damit man sie sich besser merken kann, nachdem man einmal ihre> Definition gelsen hat. So etwas nennt man auch Gedächtnisstütze (engl.> Mnemonic) und hat mit Intuition wenig bis gar nichts zu tun
Jede Fachsprache tut gut daran, der Intuition möglichst zu entsprechen.
while tut das, for oder ++ weniger. Und for(;;) noch weniger. Es
wiederspricht aber auch nicht wirklich, so dass man es übernehmen kann
mit den Jahren.
Ein Anfänger muss dann halt einmal nachschlagen. So wie jede
Operator-Prioritat auch, wenn er kein Lisp-Programm daraus machen will
;-)
Bruno V. schrieb:> Jede Fachsprache tut gut daran, der Intuition möglichst zu entsprechen.
Dummerweise sind die Menschen verschieden, einschliesslich dessen, was
sie als intuitiv empfinden. Obendrein verändert sich die Intuition mit
der Beschäftigung mit allerlei Themen, auch sprachfremden.
Wenn du also etwas als nicht intuitiv empfindest, dann kann es sein,
dass der Schöpfer der Sprache es sehr wohl so sah.
Yalu X. schrieb:> Etwas als intuitiv zu empfinden, verleitet auch dazu, das Lehrbuch zu> früh wegzulegen :)
Ja, das wäre äußerst schlimm, wenn Dinge intuitiv funktionieren würden
und man sich nicht durch furztrockene Bücher quälen müsste.
Schließlich wurde uns früher ja auch nichts geschenkt!
Lehrjahre sind keine Herrenjahre!
(prx) A. K. schrieb:> Wenn du also etwas als nicht intuitiv empfindest, dann kann es sein,> dass der Schöpfer der Sprache es sehr wohl so sah.
Mmh, ich bin mir nicht sicher, ob Du mich persönlich meinst. Ich finde
dass die Leute bei C einen guten Job gemacht haben. Mit minimalistischen
Operatoren und Zucker. Bei Pascal z.B. nehmen häufige Elemente
(procedure, begin, end) einen großen Raum ein. In Mathematik nicht. Oder
in geschriebener Sprache, wo das kleinste denkbare Zeichen (der Punkt)
die wichtigste Bedeutung hat.
Bruno V. schrieb:> Mmh, ich bin mir nicht sicher, ob Du mich persönlich meinst.
Nein, das war allgemein.
> Ich finde dass die Leute bei C einen guten Job gemacht haben.
Die Deklarationssyntax empfinde ich als Versuch, etwas intuitiv
verständlich zu machen, das völlig ins Gegenteil lief. Die ist meinen
Augen durch ihre Mischung aus Präfix- und Infix-Operatoren zur
Typentwicklung effektiv kontraintuitiv (pointer to array vs array of
pointers).
Obendrein ist sie auch noch syntaktisch schlecht aufgehängt, wie sich
bereits bei den bald nachgereichten typedefs zeigte. Aber da geht's in
die Grammatik der Sprache, in Parser und Lexer. nicht ins Visuelle.
> Mit minimalistischen> Operatoren und Zucker. Bei Pascal z.B. nehmen häufige Elemente> (procedure, begin, end) einen großen Raum ein. In Mathematik nicht.
Minimalismus ist scheiße, verwendet comments und macht Euch Freunde.
> Oder> in geschriebener Sprache, wo das kleinste denkbare Zeichen (der Punkt)> die wichtigste Bedeutung hat.
Für solche Aussagen sind manche in die Psychatrie geschickt worden ;-).
Stenographie ist auch am Ende:
https://de.wikipedia.org/wiki/Deutsche_Einheitskurzschrift#/media/Datei:Stenogr_Notiz_(Lothar_Spurzem)_2009-06B.jpg
MaWin O. schrieb:> Rolf M. schrieb:>> das sei doch so unintuitiv, weil du es wörtlich nimmst>> Wie nimmt man 'nichts' denn unwörtlich?
Man kann es an der Stelle als "Keine Bedingung" = "unbedingte
Schleifenausführung" nehmen. Das würde dann genau dem entsprechen, was C
draus macht und auch dem einzig sinnvollen, was man da draus machen
kann.
DSGV-Violator schrieb:> Minimalismus ist scheiße, verwendet comments und macht Euch Freunde
Ganz wie im realen Leben. Mathe ist scheiße und isoliert, Laberfächer
sind angesagt, machen Freunde.
Für jemanden, der mit APL anfing, liegt C jedenfalls nur kurz vor COBOL.
;-)
DSGV-Violator schrieb:> Minimalismus ist scheiße, verwendet comments und macht Euch Freunde.
Natürliche Sprache wird zum Glück nicht an Universitäten entwickelt (im
Gegensatz zu manchen Programmiersprachen).
Kein des Lesens kundiger würde "Satzbegin" "Satzende" wollen, wenn er
die Elegeanz von Majuskel und Punkt kennt. Bei Pascal hat der Herr
Wirth sich was akademisches für Anfänger überlegt.
Bruno V. schrieb:> Bei Pascal hat der Herr> Wirth sich was akademisches für Anfänger überlegt.
Das schon. Aber der Herr hatte Sinn für Grammatik. Herr Ritchie nicht.
Moin,
Was ihr alle gegen C habt:-)
Ich finde es eigentlich wegen seiner Einfachheit sogar superelegant.
Ursprünglich sollte C bekanntlich ja nur ein Zwischending zwischen ASM
und den damaligen existierenden Hochsprachen sein. Ritchie wollte es ja
hauptsächlich für Betriebssystem Einsatz vorsehen und repräsentierte
eine massive Erleichterung relativ zu ASM.
Was mich angeht, liebe ich C einfach deswegen, weil es klare
Formulierungen hat und leicht zu merken ist. Die Fußangeln der Sprache
muß man natürlich kennen. Aber man kann durchaus mit C effektiv sein.
Ist halt Geschmackssache.
Seit froh, daß es so viele Alternativen gibt, um mit jener Sprache
glücklich zu werden, die einem zusagt. Wenn nicht gerade die Firma
vorschreibt welche Sprache in Frage kommt, ist das eine reine
persönliche Entscheidung.
C++ und neue verbesserte Ansätze, wie vielleicht Rust, sind ja alle
recht gut und schön und vermeiden bekannte Schwächen von C/C++, aber
wirklich notwendig sind sie für einen großen Bereich von uC Anwendungen
auch nicht unbedingt notgedrungen.
Es ist noch nicht lange her, daß kommerzielle und freie Hersteller
Werkzeuge nur C konnten. Auch da ging es (manchmal fluchend und
murmelnd).
Nicht jeder muß in kritischen Bereichen arbeiten. Da ist dann
gleichgültig was und wie verwendet wird.
C++ und ähnliche neue Sprachstandards sind wegen der extremen
Flexibilität und Esoterik nur dann einsetzbar, wenn man fortwährend
damit arbeitet, um alle Eigenschaften der Sprache dauerhaft im
Gedächtnis zu behalten und benötigen oft Recherche um Unklarheiten zu
klären. Wer nur gelegentlich programmiert und vielleicht schon betagt
ist, wird vielleicht mit (vertrauten) C am Ende doch besser fahren.
Nicht jeder ist ein jugendliches Genie mit perfektem Gedächtnis. Im uC
Bereich lässt sich fast alles praktisch gut genug in einfacherem C
erledigen.
Ist C brauchbar? Unbedingt. Gibt es Verbesserungen? Klar. Soll halt
jeder wählen, was ihm zusagt.
Gerhard
Gerhard O. schrieb:> Ist C brauchbar? Unbedingt. Gibt es Verbesserungen? Klar. Soll halt> jeder wählen, was ihm zusagt.
Es wird heutzutage eben sehr gerne gemeckert.
Dabei wird gerne mal vergessen:
C ist vor 'nem halben Jahrhundert entwickelt worden, für Maschinen die
es vor 'nem halben Jahrhundert gab.
Und heute wird von einer gewissen Gruppe eben gemeckert.
Knapp die eine Hälfte meckert wenn es Anpassungen gibt,
knapp die andere Hälfte meckert wenn es keine Anpassungen gibt.
Der Rest hat gelesen, gelernt, ist auch mal gestolpert, hat weiter geübt
und schließlich ›C‹ für das was es kann Lieben gelernt.
Gerhard O. schrieb:> Was ihr alle gegen C habt:-)
Darf ich es gut kennen, viel genutzt haben, bis hin tief in Compilerbau.
und trotzdem Aspekte davon kritisieren? Es gibt mehr als nur Schwarz und
Weiss.
Norbert schrieb:> Knapp die eine Hälfte meckert wenn es Anpassungen gibt,> knapp die andere Hälfte meckert wenn es keine Anpassungen gibt.
3) Es gehört nicht angepasst, sondern komplett ersetzt.
> Der Rest hat gelesen, gelernt, ist auch mal gestolpert, hat weiter geübt> und schließlich ›C‹ für das was es kann Lieben gelernt.
Stehst du auf sowas? Ist ja Ok. Aber Knebel und Peitsche sind nichts für
mich.
MaWin O. schrieb:> Es gehört nicht angepasst, sondern komplett ersetzt.
Und genau das meine ich mit ›Meckern‹.
Wenn jemand noch nicht einmal ansatzweise diese Programmiersprache zu
erfassen vermag, dann flugs ab zu ›Scratch‹ oder ›Turtle-Graphics‹
Habe übrigens gerade noch einmal nachgesehen, es besteht in der Tat
keinerlei Zwang ›C‹ zu nutzen.
Wie so oft sollte man auf den guten alten Wittgenstein hören:
»Wovon man nicht sprechen kann, darüber muss man schweigen.«
Norbert schrieb:> Habe übrigens gerade noch einmal nachgesehen, es besteht in der Tat> keinerlei Zwang ›C‹ zu nutzen.
Du hast wohl noch nie in einem kommerziellen Projekt mitgearbeitet,
oder?
> Und genau das meine ich mit ›Meckern‹.
Die Wahrheit tut halt manchmal weh.
MaWin O. schrieb:> Du hast wohl noch nie in einem kommerziellen Projekt mitgearbeitet,> oder?
Selbstverständlich nicht, ich werkel' seit vierzig Jahren einfach nur so
für mich zum Vergnügen im stillen Kämmerlein. ;-)
Moin,
Warum kann man nicht:
"Jedem Tierchen, sein Pläsierchen" gönnen?
Gut. C ist über 50 Jahr und man kennt seine Stärken und Schwächen. Ihre
Existenz verdankt man bekanntlich der Tatsache, daß man überdrüssig dem
ASM wurde und eine hardwarenahe Verbesserung suchte. Das Ziel war nie,
eine Hochsprache zu werden. Für solche Zwecke ist C für uC und andere
Hardware nahe Aufgaben immer noch gut geeignet. C++ ist aber auch als
Hochsprache bewertet, wenn es auch mit Einschränkungen als Mittelsprache
geeignet ist. Irgendwie drängt sich deswegen der hinkende Vergleich
zwischen Äpfel und Birnen auf. Warum vergleicht ihr andauernd C mit C++
und alles andere darüber? Das finde ich falsch. Im geschichtlichen
Kontext findet C durchaus seinen vorgesehenen Platz.
Meine Sicht als Target Anwendung für C ist hauptsächlich embedded. Da
fällt C durchaus nicht aus seinem Rahmen und hat immer noch eine
ausreichende Existenzberechtigung und resultiert in effizienten
Binärcode.
Als Kapitän eines Schiffes hat er die primäre Verantwortung. Das Gleiche
gilt für die Design Entscheidungen des Entwicklers. Da er die
Verantwortung trägt, weiß er dann besser was er tut. Er muß entscheiden,
wo C++ besser geeignet ist wie C.
Auch wenn ihr Experten mit euren Argumenten in manchen Aspekten recht
habt, heisst das noch lange nicht, daß andere Lösungsansätze und
Werkzeugwahl notwendigerweise falsch sein müssen, nur weil ein neues
farbig angestrichenes Pferd, welches sich erst bewähren muß, im Stall
steht. Auch ein alter Klepper kann sein Last ausdauernd ziehen.
Warum streiten wir uns überhaupt? Was soll die ganze Besserwisserei? Daß
die neuesten Produkte der heutigen Zeit angepasst wurden, ist ja
verständlich und in modernen Anwendungen oft notwendig.
Ihr Entwickler (Kapitäne) habt ja die Entscheidungsgewalt; so nützt sie
weise. Aber andere wegen ihrer Entscheidung zu kritisieren, fällt
eigentlich außerhalb ihrer Kompetenz. Man wird meistens gute Gründe für
Design Entscheidungen haben. Ich habe eben Meine.
Obwohl ich ein bisschen mit C++ herum gespielt habe und mir gewisse
Aspekte ganz klar nützlich sind, finde ich aber insgesamt, daß es mir im
Kontext beschränkter uC wenig bringt mich vollkommen gescheit machen zu
müssen, nur um C++ praktisch im Umfeld des uC benützen zu wollen, ohne
viel Mühen herauszufinden, wie ressourceneffizient ich sie anwenden muß.
Bei C und meinen bisherigen Erfahrungen, weiß ich genau, was ich tun muß
oder nicht. In meinem Alter finde ich es wenig zielführend, unzählige
Stunden aufwenden zu müssen, nur um in C++ efizient funktionieren zu
können. Fakt ist, wenn man nicht andauernd das Neue übt, man es bald
wieder vergisst. So gesehen bin ich mit einer Programmiersprache die ich
gut kenne doch besser dran.
Man mag das sehen, wie man will. Jeder soll doch so vorgehen wie es ihm
vernünftig erscheint und tolerant anderen gegenüber sein, die eben
anders denken und glücklich damit werden. Ich habe überhaupt nichts
gegen C++, ausser, daß es mir zu viel Zeitaufwand verursacht, um es
gründlich genug lernen zu können, so dass es mir auch etwas nützt. Ich
brauche es im Kontext meiner Interessen nicht, und das, sollte genügen.
Was nützt es, Anderen gegenüber abfällig zu sein, nur weil man denkt,
man weiß es besser. Jeder hat für seine Denkweise und Logik seine
Gründe. Da sollte man tolerant genug sein, Denkweisen Anderer zu
respektieren.
Dieser ganze Streit um den Bart der Sprachen, find ich wenig
zielführend.
Es gibt Leute, die bauen mit einfachsten Werkzeugen ein tolles Holzhaus
in der Wildnis. Es gibt andere, die brauchen dazu eine Fabrik mit
Werkzeugpark. Das gilt auch sinngemäß für uC Anwendungen.
Gerhard
Gerhard O. schrieb:> Warum kann man nicht:>> "Jedem Tierchen, sein Pläsierchen" gönnen?> ...
TL;DR
Du beklagst einen Stellungskrieg zwischen den C und den C++-Jüngern?
Normalerweise bin ich ja dafür zuständig, so etwas anzuzetteln ... doch
aber nicht wirklich hier wegen meiner nur halb-ernst gemeinten
Vorschläge ala `repeat<>` , etc.???
Trotzdem bin ich der Meinung, dass jeder C-Entwickler von den vielen
kleinen Goodies aus C++ profitieren kann. Das habe ich hier schon in
ganz vielen Beiträgen auch beispielhaft unterlegt.
Natürlich sind C und C++ unterschiedliche Programmiersprachen, C ist
kein Subset von C++, und einige Details sind gefährlich unterschiedlich.
Trotzdem schätze ich, das 90% der hier besprochenen Projekte mit
Problemen, einfach als C++ kompiliert werden könnten, und man dann
langsam ein paar Goodies aus C++ einfügen könnte. Man könnte also
einfach versuchen, wenig zu ändern und doch viel zu profitieren.
Wilhelm M. schrieb:> Du beklagst einen Stellungskrieg zwischen den C und den C++-Jüngern?
Der ist ganz einfach zu lösen, indem man beide auf den Misthaufen der
Geschichte wirft.
Wilhelm M. schrieb:> Gerhard O. schrieb:>> Warum kann man nicht:>>>> "Jedem Tierchen, sein Pläsierchen" gönnen?>> ...>> TL;DR>> Du beklagst einen Stellungskrieg zwischen den C und den C++-Jüngern?> Normalerweise bin ich ja dafür zuständig, so etwas anzuzetteln ... doch> aber nicht wirklich hier wegen meiner nur halb-ernst gemeinten> Vorschläge ala `repeat<>` , etc.???>> Trotzdem bin ich der Meinung, dass jeder C-Entwickler von den vielen> kleinen Goodies aus C++ profitieren kann. Das habe ich hier schon in> ganz vielen Beiträgen auch beispielhaft unterlegt.>> Natürlich sind C und C++ unterschiedliche Programmiersprachen, C ist> kein Subset von C++, und einige Details sind gefährlich unterschiedlich.> Trotzdem schätze ich, das 90% der hier besprochenen Projekte mit> Problemen, einfach als C++ kompiliert werden könnten, und man dann> langsam ein paar Goodies aus C++ einfügen könnte. Man könnte also> einfach versuchen, wenig zu ändern und doch viel zu profitieren.
Hallo Wilhelm,
Wegen TLDR, naja, ich habe nichts gehen C++ und verwende es auch in
homöopathischen Dosen, wo es mir nützlich ist und intuitiv genug zum
merken. However, ich habe keinen wirklichen Grund, mich als
Gelegenheitsprogrammierer komplett einzuarbeiten, weil ich viele
kritische Details wieder vergessen würde. Übung macht den Meister; aber
wenn ich nur alle sechs Monate etwas durchziehe, reicht es doch nicht.
Ich bin 69 und habe nicht mehr dasselbe Gedächtnis eines Jungspunds. Es
geht nicht um die Philosophie von C++, sondern um die Praxis in meinem
Kontext und habe überhaupt keine negative Einstellung C++ gegenüber, ich
finde es einfach zu spezialisiert in Bezug auf den nächsten Abschnitt.
Ich verwende einige uC Familien diverser Hersteller deren Werkzeuge nur
C können und habe Gründe gewisse Teile oder Apps zu Portieren. Da müsste
ich unter GCC C++ geschriebene Teile wieder auf C faktorisieren. Da
bleibe ich lieber allgemein bei neutralen C wegen der Portabilität um es
mir nicht anzutun. Ich muß auf meine vorhandenen Werkzeuge Rücksicht
nehmen. Und PC Entwicklung jache ich nicht. Für embedded reichen mir
meine Möglichkeiten.
Gerhard
MaWin O. schrieb:> Wilhelm M. schrieb:>> Du beklagst einen Stellungskrieg zwischen den C und den C++-Jüngern?>> Der ist ganz einfach zu lösen, indem man beide auf den Misthaufen der> Geschichte wirft.
Nichts für ungut. Aber manche Deiner Kommentare finde ich wenig
konstruktiv:-)
It is very difficult to tell if a given loop is infinite.
4
Infinite loops are rare and typically unintentional.
5
There are many loop optimizations that are only valid for non-infinite loops.
6
The performance wins of these optimizations are deemed important.
7
Some compilers already apply these optimizations, making infinite loops non-portable too.
8
Therefore, we should declare programs with infinite loops undefined behavior, enabling the optimizations.
also etwa,
* Ein Code-schnüppsel einer Schleife sieht man schwer an, ob es
unendlich läuft.
* Unendliche Schleifen sid selten und meist unbeabsichtigt.
* Viele Schleifenoptimierung sind nur für endliche Schleifen valide.
* Diese Schleiefenoptimierungen gelten als wichtig.
* Einige Compiler benutzen diese Optimierungen, deshalb sind solche
unendlichen schleifen nicht compiler-unabhängig.
* Deshal sollten wir Programme mit unendlichen Schleifen zu solchen mit
"undefined behaviour" deklarieren, um so die Optimierung zu ermöglichen.
DSGV-Violator schrieb:> Jörg W. schrieb:>> Passt halbwegs hierher, denke ich, denn es geht auch um Endlosschleifen.>> :-) Geisterte gerade durch die WG14.>>>> https://research.swtch.com/ub>> Zusammenfassung:
Das ist die Zusammenfassung ausschließlich des Hans-Boehm-Papiers (und
nicht etwa des ganzen Artikels).
> Das ist die Zusammenfassung ausschließlich des Hans-Boehm-Papiers (und> nicht etwa des ganzen Artikels).
Was fehlt den aus dem Artikel zum Thema "unendliche ("for") Schleifen im
C-Quelltext"?
Es geht im Artikel halt um einiges mehr, und dieser Thread hier befasst
sich ja nun auch an vielen Stellen mit (Un-)Schönheiten von C als
solches. Daher sei die komplette Lektüre jedem angeraten.
Man sollte natürlich immer im Hinterkopf behalten, dass der Artikel
schlicht eine Meinung einer Person ist. Mit der kann man übereinstimmen
oder auch nicht.
Jörg W. schrieb:> Passt halbwegs hierher, denke ich, denn es geht auch um Endlosschleifen.> :-) Geisterte gerade durch die WG14.>> https://research.swtch.com/ub
So wie ich das lese, wird argumentiert alle Endlosschleifen sollen UB
sein, auch solche, die Seiteneffekte haben. Jedenfalls wird nicht auf
Seiteneffekte der ersten Schleife verwiesen.
Johann L. schrieb:> Jörg W. schrieb:>> Passt halbwegs hierher, denke ich, denn es geht auch um Endlosschleifen.>> :-) Geisterte gerade durch die WG14.>>>> https://research.swtch.com/ub>> So wie ich das lese, wird argumentiert alle Endlosschleifen sollen UB> sein, auch solche, die Seiteneffekte haben. Jedenfalls wird nicht auf> Seiteneffekte der ersten Schleife verwiesen.
Das denke ich nicht. Endlosschleifen mit Seiteneffekten sind von der
Argumentation nicht betroffen, denn Ausgangspunkt war die neue
Formulierung in 6.8.5p6:
1
An iteration statement that performs no input/output operations,
2
does not access volatile objects, and performs no
3
synchronization or atomic operations in its body, controlling
4
expression, or (in the case of a for statement) its expression-3,
5
may be assumed by the implementation to terminate.
Wilhelm M. schrieb:> may be assumed by the implementation to terminate.
Cool. Bei vielen (den meisten?) Mikrocontroller-Programmen führt
Terminieren dann wieder in eine Endlosschleife ;)
An iteration statement may be assumed by the implementation to terminate if its controlling
2
expression is not a constant expression200), and none of the following operations are performed in its
3
body, controlling expression or (in the case of a for statement) its expression-3201):
4
(…)
Das heißt also, dass just der hier im Thread genannte Fall, egal ob
"while(true)", "while(1)" oder "for(;;)" explizit als Endlosschleife
implementiert werden muss.
Liebe Mitforenten,
ihr enttäuscht mich! Da verhunzt ein Newbie den Namen des lieben Peter
https://de.m.wikipedia.org/wiki/Peter_Naur, und keiner weist ihn
zurecht!
LG, Sebastian
Frank M. schrieb:> Rolf M. schrieb:>>for(;;)> volatile int i; i = 42;>> Geschweifte Klammern vergessen?
Ja.
Jörg W. schrieb:> Rolf M. schrieb:>> Also etwa sowas?>> Von den fehlenden geschweiften Klammern abgesehen: auch sowas darf nicht> wegoptimiert werden:> for (;;) {}
Ich dachte, das sei die Aussage des obigen Zitats aus dem Standard. Der
Compiler darf annehmen, dass diese Schleife terminiert (warum auch
immer) und damit auch z.B. den Code, der danach kommt, ausführen.
Seit C11 / C++11 und der Einführung des Memory-Models haben C und C++
etwas unterschiedliche Begriffe von forward-progress. Das führt dazu,
dass endlos-Schleifen ohne Seiteneffekte in C++ UB sind und in C nicht.
Bei trivialen endlos-Schleifen ist das sogar sichtbar. Ein Beispiel ist
etwa folgendes:
1
#include<stdio.h>
2
3
intmain(){
4
while(1)
5
;
6
}
7
8
voidunreachable(){
9
printf("xxx\n");
10
}
Mit clang++ -O2 wird hier "xxx" ausgegeben! Die Schleife wird entfernt
(UB), es bleibt im ASM das main-label, was dann auf derselbe Adresse wie
unreachable liegt.
Wilhelm M. schrieb:> Seit C11 / C++11 und der Einführung des Memory-Models haben C und C++> etwas unterschiedliche Begriffe von forward-progress. Das führt dazu,> dass endlos-Schleifen ohne Seiteneffekte in C++ UB sind und in C nicht.> Bei trivialen endlos-Schleifen ist das sogar sichtbar. Ein Beispiel ist> etwa folgendes:> ...
Interessant. Gibt es auch ein Beispiel, wo dieser Unterschied zu einem
Vorteil in C++ führt, bspw. in Form einer besseren Optimierung, die in C
nicht möglich ist?
Rolf M. schrieb:> Der Compiler darf annehmen, dass diese Schleife terminiert
Nein, denn sie hat einen "constant controlling expression". Nur für
Schleifen, die das nicht haben und nicht eine der nachfolgenden
Aktionen ausführen (die ich nicht mit zitiert habe), darf der Compiler
annehmen, dass sie irgendwann terminieren.
Wilhelm M. schrieb:> Das führt dazu, dass endlos-Schleifen ohne Seiteneffekte in C++ UB sind> und in C nicht.
Was im Umkehrschluss heißt, dass C++ für MCUs eigentlich tabu ist, denn
dort kann eine Endlosschleife ohne (sichtbare) Seiteneffekte essenziell
sein.
Jörg W. schrieb:> Was im Umkehrschluss heißt, dass C++ für MCUs eigentlich tabu ist, denn> dort kann eine Endlosschleife ohne (sichtbare) Seiteneffekte essenziell> sein.
Wer in seinem Code UB verwendet, ist selbst Schuld. Dies ist aber kein
Problem der Sprache, sondern des Programmierers! Deswegen: natürlich ist
C++ (genauso wie C) absolut gut für MCU geeignet. Auch in C kann ich UB
produzieren (ja: nicht durch dieses Konstrukt), aber deswegen die
Sprache C als ungeeignet abzustempeln, machst Du ja auch nicht.
Formell hat ein C++-Programm, was mit einer leeren Endlos-Schleife
geschrieben ist, und deswegen ISRs enthalten muss, wenn es irgendetwas
sinnvolles tun soll, noch ein weiteres Problem: es ist nämlich
strenggenommen kein valides C++ Programm. Zwar existieren im
C++-Standard Signal-Handler, die per signal() registriert werden, und
man könnte sie zu ISTs ähnlich betrachten, aber: ähnlich ist nicht
gleich im Sinne des Standards.
Also anders herum formuliert: wer also ein C++-Programm durch die
Verwendung von ISRs als nicht konformes Programm darstellt, der sollte
schon wissen was er tut, und da ist diese Endlos-Schleife das kleinste
Problem.
Wilhelm M. schrieb:> Jörg W. schrieb:>> Was im Umkehrschluss heißt, dass C++ für MCUs eigentlich tabu ist, denn>> dort kann eine Endlosschleife ohne (sichtbare) Seiteneffekte essenziell>> sein.>> Formell hat ein C++-Programm, was mit einer leeren Endlos-Schleife> geschrieben ist, und deswegen ISRs enthalten muss, wenn es irgendetwas> sinnvolles zun soll, noch ein weiteres Problem: es ist nämlich> strenggenommen kein valides C++ Programm.
Eine praktischere Anwendung für eine Endlos-Schleife ist z.B. "warten
auf den Watchdog Reset". Das kann man auch in einem ansonsten "normalen"
C++-Programm gebrauchen. Deswegen bleibt das Programm doch valide. Womit
könnte man so eine Endlos-Schleife norm-konform ersetzen?
Bauform B. schrieb:> Eine praktischere Anwendung für eine Endlos-Schleife ist z.B. "warten> auf den Watchdog Reset". Das kann man auch in einem ansonsten "normalen"> C++-Programm gebrauchen. Deswegen bleibt das Programm doch valide. Womit> könnte man so eine Endlos-Schleife norm-konform ersetzen?
Geht nicht: ein C++-Programm ohne Seiteneffekte ist schlicht invalide.
1
The implementation may assume that any thread will eventually do one of the following:
2
(1.1) — terminate,
3
(1.2) — make a call to a library I/O function,
4
(1.3) — perform an access through a volatile glvalue, or
5
(1.4) — perform a synchronization operation or an atomic operation.
Aber wie gesagt: die Watchdog-Exception oder -Reset ist auch etwas, was
so im C++-Standard nicht betrachtet wird.
Yalu X. schrieb:> Wilhelm M. schrieb:>> Seit C11 / C++11 und der Einführung des Memory-Models haben C und C++>> etwas unterschiedliche Begriffe von forward-progress. Das führt dazu,>> dass endlos-Schleifen ohne Seiteneffekte in C++ UB sind und in C nicht.>> Bei trivialen endlos-Schleifen ist das sogar sichtbar. Ein Beispiel ist>> etwa folgendes:>> ...>> Interessant. Gibt es auch ein Beispiel, wo dieser Unterschied zu einem> Vorteil in C++ führt, bspw. in Form einer besseren Optimierung, die in C> nicht möglich ist?
Es ist der Umkehrschluss: wenn Endlos-Schleifen zu einem invaliden
C++-Programm führen, dann folgt daraus, dass ein valides C++-Programm
kein Endlos-Schleifen enthält. Sprich: der Compiler kann annehmen, dass
jede Schleife terminiert! Er muss es nicht mehr beweisen, was ja das
Halte-Problem wäre ;-)
Und damit kann er bspw. aufeinanderfolgende Schleifen zu einer zusammen
fassen. Und das ist ein Performance Vorteil (im Paper von H. Boehm war
ein Beispiel).
Wilhelm M. schrieb:> Es ist der Umkehrschluss: wenn Endlos-Schleifen zu einem invaliden> C++-Programm führen, dann folgt daraus, dass ein valides C++-Programm> kein Endlos-Schleifen enthält. Sprich: der Compiler kann annehmen, dass> jede Schleife terminiert! Er muss es nicht mehr beweisen, was ja das> Halte-Problem wäre ;-)
Dazu noch ein Beispiel:
1
#include<stdio.h>
2
#include<stdint.h>
3
4
staticlongcollatz_conjecture(longi){
5
while(i!=1){
6
if((i%2)==0)
7
i/=2;
8
else
9
i=i*3+1;
10
}
11
returni;
12
}
13
14
15
intmain(){
16
returncollatz_conjecture(42);
17
}
Der C++-Compiler (g++ -O3) produziert daraus ein simples
1
main:
2
movl$1,%eax
3
ret
Und der C Compiler (gcc -O3):
1
main:
2
movl$42,%eax
3
.L7:
4
testb$1,%al
5
jne.L2
6
movq%rax,%rdx
7
shrq$63,%rdx
8
addq%rdx,%rax
9
sarq%rax
10
cmpq$1,%rax
11
jne.L7
12
movl$1,%eax
13
ret
14
.L2:
15
leaq1(%rax,%rax,2),%rdx
16
.L5:
17
testb$1,%dl
18
jne.L6
19
movq%rdx,%rax
20
shrq$63,%rax
21
addq%rdx,%rax
22
sarq%rax
23
jmp.L7
24
.L6:
25
leaq1(%rdx,%rdx,2),%rdx
26
jmp.L5
Hat der C++-Compiler die Collatz-Annahme bewiesen? Wohl kaum. Es nimmt
einfach an, dass die Schleife bei i == 1 terminiert.
Johann L. schrieb im Beitrag #7484365:
> Die Optimierung zu "return 1" wird aber auch ohne Call aus main> durchgeführt wenn man vor der Schleife i = 42 setzt.
Johann L. schrieb im Beitrag #7484365:
> Die Optimierung zu "return 1" wird aber auch ohne Call aus main> durchgeführt wenn man vor der Schleife i = 42 setzt.>> Hat also nix mit der zitierten Stelle aus dem C++ Standard zu tun.
Warum? Das ändert doch nichts. Wo die 42 herkommt hat doch nichts damit
zu tun, dass der Compiler aus dem "i |= 1" im Schleifenkopf
schlussfolgert, dass die Schleife terminiert und i danach den Wert 1
hat.
Wilhelm M. schrieb:> Wer in seinem Code UB verwendet, ist selbst Schuld.
Nur dass, im Gegensatz zu C++, das analoge C-Programm eben gerade kein
undefined behaviour zeigt. Dort ist die Endlosschleife mit konstanter
Schleifenbedingung legal und definiert.
Damit ist es in der Tat ein Problem der verwendeten Sprache – auch ohne
eine explizite Endlosschleife, wie sie bspw. für Rust genannt worden
ist.
Jörg W. schrieb:> Damit ist es in der Tat ein Problem der verwendeten Sprache – auch ohne> eine explizite Endlosschleife, wie sie bspw. für Rust genannt worden> ist.
Ich weiß ja, dass Du lieber Haskell statt C++ magst. Aber nochmal: wenn
ein Programmierer nicht auf die Unterschiede zwischen
Programmiersprachen achtet, und damit in der einen Sprache UB
produziert, ist das nicht Problem der Sprache, sondern des
Programmierers.
Wilhelm M. schrieb:> Ich weiß ja, dass Du lieber Haskell statt C++ magst.
nö
Wilhelm M. schrieb:> In C++ garantiert UB-frei.
Nur, falls nicht gerade jemand sleep irgendwie so definiert hat:
1
#ifndef DEBUG
2
# define sleep() _cpu_sleep()
3
#else
4
/* do not sleep when debugging */
5
# define sleep()
6
#endif
Ich bleibe dabei, dass ich die C++-UB an dieser Stelle für eine eher
nutzlose und gefährliche Geschichte halte. Da es in C kein UB ist, gibt
es eigentlich auch keine wirkliche Rechtfertigung dafür.
Hans H. schrieb:> Ich schreibe die Endlosschleife immer so:> do {> // many> // lines> // of> // code> } while (1=1);>> denn ich finde die Überraschung muß am Ende kommen.
Weil manche ein fehlendes = moniert haben :), hier eine bessere Version:
Da hat man dann auch eine schöne Abreißkante beim Typenraddrucker,
denn der Code danach wird ja nicht ausgeführt.
Oder gerade doch wenn man den obigen Ausführungen folgen sollte...
Wilhelm M. schrieb:> Hat der C++-Compiler die Collatz-Annahme bewiesen? Wohl kaum. Es nimmt> einfach an, dass die Schleife bei i == 1 terminiert.
Kann es sein daß der Compiler einfach erkennt daß die Funktion nur mit
einer Konstante aufgerufen wird?
Wenn das Argument ein Nutzerinput ist, was dann? Das Microsoft C++ wirft
die Funktion dann jedenfalls nicht raus.
Hier ist noch ein (zugegebenermaßen etwas spezielles) Beispiel, wo die
Behandlung von Endlosschleifen nach dem C-Standard vorteilhaft sein
kann:
Wilhelm M. schrieb:> long collatz_conjecture(long i){> ...
Ein pfiffiger Mathematiker möchte herausfinden, ob in der (unendlichen)
Collatz-Folge mit dem Startwert 42 die 7 vorkommt. Natürlich kann man
auch ohne Computer leicht beweisen, dass dies nicht der Fall ist. Da der
Mathematiker aber möglichst zielgerichtet vorgehen und möglichst wenig
seiner Denkzeit investieren möchte, beschließt er, vorab mit Hilfe des
Computers eine erste Vermutung zu generieren. Er nimmt also das von
Wilhelm gepostete Programm und ersetzt darin die Zeile
1
while(i!=1){
durch
1
while(i!=7){
Er kompiliert das Programm als C-Programm und lässt es maximal 5 min
laufen. Es gibt nun zwei Möglichkeiten:
1. Das Programm terminiert schon vor Ablauf der 5 min. Das lässt sehr
stark vermuten, dass die 7 in der Folge vorkommt.
2. Das Programm terminiert nach den 5 min noch nicht. Dies lässt
zumindest erahnen, dass die 7 möglicherweise nicht in der Folge
enthalten ist.
In beiden Fällen hat er zwar nur eine Vermutung, aber so eine Vermutung
kann bei der anschließenden formalen Beweisführung helfen, Sackgassen zu
vermeiden und damit Denkzeit zu sparen.
Mit C++ funktioniert diese Vorgehensweise wegen des UB nicht so ohne
weiteres. Natürlich kann man in die Schleife irgendeinen Seiteneffekt
(bspw. den Zugriff auf eine volatile-Variable) einbauen. Das macht aber
den Code langsamer, so dass innerhalb der 5 min weniger Iterationen
ausgeführt werden, was wiederum die resultierende Vermutung schwächt.
Yalu X. schrieb:> Hier ist noch ein (zugegebenermaßen etwas spezielles) Beispiel, wo die> Behandlung von Endlosschleifen nach dem C-Standard vorteilhaft sein> kann:
Du solltest allerdings bedenken, dass auch bei C der Compiler genau
diese Optimierung durchführen darf:
Nochmal aus dem C-Standard:
In meiner obigen Funktion ist genau so eine Iteration drin. Die
Bedingung ist keine constant-expression und die Berechnung enthält keine
Seiteneffekte.
Der Compiler nimmt an, dass sie terminiert: für i == 1 in meinem Fall
oder i == 7 in Deinem Fall. Also hier steht bzgl. der mögl. Optimierung
kein Unterschied zwischen C und C++. Und der Clang / Clang++ machen das
auch gleich. Beim GCC schein es ein missing-optimization-bug zu sein.
Daher stimmt Deine obige Aussage nur für einen Compiler, der diese mögl.
Optimierung nicht nutzt.
Wilhelm M. schrieb:> Yalu X. schrieb:>> Hier ist noch ein (zugegebenermaßen etwas spezielles) Beispiel, wo die>> Behandlung von Endlosschleifen nach dem C-Standard vorteilhaft sein>> kann:>> Du solltest allerdings bedenken, dass auch bei C der Compiler genau> diese Optimierung durchführen darf:
Stimmt.
Ich bin irrtümlicherweise (und ohne lange darüber nachzudenken) davon
ausgegangen, dass du mit dem Collatz-Beispiel die Unterschiede zwischen
den beiden Standards und nicht nur die Unterschiede zwischen clang++ und
gcc aufzeigen wolltest.
Ich denke, die ganze Verwirrung bzw. Unklarheit zwischen WG14 und WG21
liegt in folgendem:
1) C++ definiert 6.9.2.3 intro.progess was ein Thread (Kontrollfluss) zu
tun hat. Und da ist in jedem Fall irgendwann einmal einen Seiteneffekt
auszulösen.
2) C definiert in 6.8.5 Iteration statements
2.1) in Satz 3 wie jede Iteration zu behandeln ist, und
2.2) in Satz 4 den Spezialfall ein Iteration mit nicht-konstanter
Bedingung ohne Seiteneffekte.
Aus 1) folgt, dass in C++ Endlos-Schleifen ohne Seiteneffekte UB sind
(nicht-valide), und die Fußnote sagt explizit, dass dieses zu
Optimierungszwecken genutzt werden kann.
In dem hier gezeigten Beispiel besteht die Optimierung daraus,
anzunehmen, dass die Schleife auch ohne Beweis terminiert.
Bei der trivialen Endlos-Schleife for(;;) {} kann der Compiler trivial
beweisen, dass die Schleife nicht terminiert, daher ist sie UB, und darf
entfernt werden.
Aus 2.2) folgt auch für C wie in C++ die Optimierung der Schleife wie in
1)
Aus 2.1) folgt allerdings, dass ein triviale Endlos-Schleife for(;;){}
kein UB ist.
Bis C++03 War in C++ die Formulierung unter 1) nicht drin. Damit war
auch in C++03 die triviale Endlos-Schleife kein UB.
In C99 war 2.2) nicht drin, damit hatte der C-Compiler diese
Optimierungsmöglichkeit nicht. Das ist vllt der Grund für den GCC
missing-optimization-bug.
Es gibt jetzt Bestrebungen (so wie ich das beobachte), die
Formulierungen zu vereinheitlichen.
Wilhelm M. schrieb:> Bei der trivialen Endlos-Schleife for(;;) {} kann der Compiler trivial> beweisen, dass die Schleife nicht terminiert, daher ist sie UB, und darf> entfernt werden.
Genau diese Mentalität "ist UB, also darf der Compiler eh machen, was er
will" ist ja, was das von mir referenzierte Paper insgesamt kritisiert:
"Prioritize Performance over Correctness".
Jörg W. schrieb:> Wilhelm M. schrieb:>> Bei der trivialen Endlos-Schleife for(;;) {} kann der Compiler trivial>> beweisen, dass die Schleife nicht terminiert, daher ist sie UB, und darf>> entfernt werden.>> Genau diese Mentalität "ist UB, also darf der Compiler eh machen, was er> will" ist ja, was das von mir referenzierte Paper insgesamt kritisiert:> "Prioritize Performance over Correctness".
Absolut,
und das gilt für beide Sprachen C und C++! (Manchmal in der Diskussion
hatte ich den Eindruck, dass sei mal wieder nur ein C++ Problem)
Blöderweise gibt es Endlosschleifen ohne vom Compiler erkennbare
Nebeneffekte, die diese aber in Hardware haben. Ein Beispiel ist der
Weg, wie AVRs sich selbst zurücksetzen: Watchdog aktivieren, Interrupts
ggf deaktivieren, und dann for(;;){}. Wäre dann schon gut, wenn der
Compiler das nicht wegoptimiert. Ähnlich läuft es bei Programmen, die
sämtliche Aktivitäten in Interrupts erledigen.
(prx) A. K. schrieb:> Blöderweise gibt es Endlosschleifen ohne vom Compiler erkennbare> Nebeneffekte, die diese aber in Hardware haben. Ein Beispiel ist der> Weg, wie AVRs sich selbst zurücksetzen: Watchdog aktivieren, Interrupts> ggf deaktivieren, und dann for(;;){}.
Den Watchdog aktivieren hat mit der Schleife aber nichts zu tun.
> Wäre dann schon gut, wenn der> Compiler das nicht wegoptimiert. Ähnlich läuft es bei Programmen, die> sämtliche Aktivitäten in Interrupts erledigen.
Ja klar, ich hatte oben schon ein Lösung dargestellt.
Wilhelm M. schrieb:> Absolut,> und das gilt für beide Sprachen C und C++!
Dann sind wir ja mal einer Meinung. :-)
> (Manchmal in der Diskussion> hatte ich den Eindruck, dass sei mal wieder nur ein C++ Problem)
Ist es eher zufällig in diesem ganz speziellen Fall, ansonsten sind sie
sich ja in vielen sehr ähnlich.
Hallo,
jetzt habt ihr mich völlig vom Glauben abgebracht. Es hieß immer
Seiteneffekte sind nicht gut und müssen vermieden werden. Jetzt soll man
Seiteneffekte einbauen damit es nicht UB ist? Ich komme ehrlich gesagt
nicht mehr mit.
Das kleinste C/C++ Programm lautet
Jörg W. schrieb:> Das ist aber deshalb inkorrekt, weil es einen Rückgabewert liefern muss,> jedoch keinen erzeugt.
Nein.
main() ist besonders, dass es implizit 0 zurück gibt.
Veit D. schrieb:> Es hieß immer> Seiteneffekte sind nicht gut und müssen vermieden werden.
Der Begriff Seiteneffekt ist nicht genau definiert, in diesem Kontext
bedeutet es eher "observable effect", entsprechend den Aktionen, die die
Standards erwähnen.
Jörg W. schrieb:> Wilhelm M. schrieb:>> Nein.>> main() ist besonders, dass es implizit 0 zurück gibt.>> OK, das war mir nicht bewusst.
main() hat auch in C mehrere Signaturen, ist also gewissermaßen implizit
überladen.
Wilhelm M. schrieb:> main() hat auch in C mehrere Signaturen, ist also gewissermaßen implizit> überladen.
Ja, aber (im hosted environment) geben sie alle "int" zurück, nur die
Parameterliste kann entweder (void) sein (was in C nicht identisch zur
leeren Liste in Veits Beispiel ist) oder (int, char **).
Jörg W. schrieb:> Wilhelm M. schrieb:>> main() hat auch in C mehrere Signaturen, ist also gewissermaßen implizit>> überladen.>> Ja, aber (im hosted environment) geben sie alle "int" zurück,
gehört nicht zur Signatur
> nur die> Parameterliste kann entweder (void) sein (was in C nicht identisch zur> leeren Liste in Veits Beispiel ist) oder (int, char **).
... und eine beliebige weitere!
z.B int main(int argc, char *argv[], char *envp[])
Und als freestanding muss es noch nicht mal main() sein.
Jörg W. schrieb:> Wilhelm M. schrieb:>> Nein.>> main() ist besonders, dass es implizit 0 zurück gibt.>> OK, das war mir nicht bewusst.
WIMRE aber erst ab C99.
Wilhelm M. schrieb:>> Ja, aber (im hosted environment) geben sie alle "int" zurück,>> gehört nicht zur Signatur
Ist aber im Standard vorgeschrieben.
> Und als freestanding muss es noch nicht mal main() sein.
Korrekt, aber freestanding schaltet allerlei Optimierungen ab, die
Annahmen bezüglich der Standardbibliothek treffen. Bspw. kann der
Compiler dann "strlen("foo")" nicht mehr einfach durch die Konstante 3
ersetzen. Daher meide ich das persönlich selbst in Umgebungen, die
eigentlich den Charakter von "freestanding" haben (wie MCUs).
Wilhelm M. schrieb:> Veit D. schrieb:>> Das kleinste C/C++ Programm lautetint main()>> { }>> steht in allen Büchern.>> Perfekt. Wo ist das Problem?
Es hat keine Seiteneffekte, ist also UB in C++. Oder gibt es noch ne
Regel, dass dieser Fall nicht UB ist?
Johann L. schrieb:> Wilhelm M. schrieb:>> Veit D. schrieb:>>> Das kleinste C/C++ Programm lautetint main()>>> { }>>> steht in allen Büchern.>>>> Perfekt. Wo ist das Problem?>> Es hat keine Seiteneffekte, ist also UB in C++. Oder gibt es noch ne> Regel, dass dieser Fall nicht UB ist?
Es terminiert.
Jörg W. schrieb:> Korrekt, aber freestanding schaltet allerlei Optimierungen ab, die> Annahmen bezüglich der Standardbibliothek treffen.
Wo steht das?
Was hat das mit main() zu tun?
Ist das eine vorgeschriebene Optimierung wie bspw. copy-elision oder
NRVO?
Wilhelm M. schrieb:> Hans H. schrieb:>> Kann es sein daß der Compiler einfach erkennt daß die Funktion nur mit>> einer Konstante aufgerufen wird?>> Nein.> Probiere> volatile long r;> int main() {> return collatz_conjecture(r);> }
Dein Beispiel ist UB, da auf r ohne Initialisierung zugegriffen wird.
Da kann der Compiler machen was er will.
Ich hab mal mit godbolt.org und clang 16.0.0 x86-64 folgendes übersetzen
lassen:
1
#include <iostream>
2
#include <cstdlib>
3
4
static unsigned long collatz_conjecture(unsigned long i) {
5
while (i != 1) {
6
if ((i % 2) == 0)
7
i /= 2;
8
else
9
i = i * 3 + 1;
10
}
11
return i;
12
}
13
int main(int argc, const char* argv[])
14
{
15
if (argc > 1) {
16
unsigned long l{ strtoul(argv[1], nullptr, 10) };
17
std::cout << collatz_conjecture(l) << std::endl;
18
}
19
}
und das Assemblerlisting zeigt daß er die Funktion so implementiert wie
sie geschrieben steht.
Wilhelm M. schrieb:> ich hatte oben schon ein Lösung dargestellt.
Ja wie sieht denn eine leere Endlosschleife in C++ nun aus?
Im Standard stehen ja nur Brainfuck-Argumente was nicht geht.
Aber wie geht es denn nun?
z.B. eine lokale volatile Variable zu setzen wäre zwar konform, aber
absoluter Overkill weil Compiler solche Variablen nicht in Registern
anlegen sondern im Frame! Man brauch also nicht nur einen Frame, sondern
falls er nicht wegoptimiert werden kann sogar noch einen Frame-Pointer.
Beispiel: avr-g++.
Und Dinge wie __asm volatile ("":); sind nicht durch den Standard
abgedeckt und nicht portabel.
Johann L. schrieb:> Wilhelm M. schrieb:>> ich hatte oben schon ein Lösung dargestellt.>> Ja wie sieht denn eine leere Endlosschleife in C++ nun aus?
Geht nicht, soweit ich weiß (s.o.).
>> Im Standard stehen ja nur Brainfuck-Argumente was nicht geht.>> Aber wie geht es denn nun?>> z.B. eine lokale volatile Variable zu setzen wäre zwar konform, aber> absoluter Overkill weil Compiler solche Variablen nicht in Registern> anlegen sondern im Frame! Man brauch also nicht nur einen Frame, sondern> falls er nicht wegoptimiert werden kann sogar noch einen Frame-Pointer.> Beispiel: avr-g++.>> Und Dinge wie __asm volatile ("":); sind nicht durch den Standard> abgedeckt und nicht portabel.
Das ist es keine "leere" Endlos-Schleife mehr, und sie hat
Seiteneffekte.
Wie gesagt, würde ich mir nicht so große Gedanken machen, weil auch ISRs
nicht vom Standard gedeckt sind. Also ein C++-Programm mit ISRs ist
einfach nicht Standard-konform (s.o. hatte ich schon geschrieben), damit
erübrigt sich die Frage nach der Schleife.
Wilhelm M. schrieb:> Johann L. schrieb:>> Wilhelm M. schrieb:> Das ist es keine "leere" Endlos-Schleife mehr, und sie hat> Seiteneffekte.
Jetzt mal Butter bei die Fisch und nicht immer drumrumreden. Mach's mal
explizit! Was kommt am nächsten an wheil(1); ran? Ideralerweise so,
dass auf Asm-Ebene nur ne leere Schleife bleibt.
> Wie gesagt, würde ich mir nicht so große Gedanken machen, weil auch ISRs> nicht vom Standard gedeckt sind.
Sind die jetzt auch UB???
Johann L. schrieb:> Wilhelm M. schrieb:>> Johann L. schrieb:>>> Wilhelm M. schrieb:>> Das ist es keine "leere" Endlos-Schleife mehr, und sie hat>> Seiteneffekte.>> Jetzt mal Butter bei die Fisch und nicht immer drumrumreden. Mach's mal> explizit!
Kannst Du nicht lesen?
>>> Wie gesagt, würde ich mir nicht so große Gedanken machen, weil auch ISRs>> nicht vom Standard gedeckt sind.>> Sind die jetzt auch UB???
Nein, aber sie existieren einfach nicht.
Wilhelm M. schrieb:> Johann L. schrieb:>> Jetzt mal Butter bei die Fisch und nicht immer drumrumreden. Mach's mal>> explizit! Was kommt am nächsten an while(1); ran? Ideralerweise so,>> dass auf Asm-Ebene nur ne leere Schleife bleibt.>> Kannst Du nicht lesen?
Doch. Aber ich find's einfach nicht. Nur den Beitrag
Wilhelm M. schrieb:> Ja klar, ich hatte oben schon ein Lösung dargestellt.
der aber nicht auf die Lösung verweist. Und "oben" sind > 300 Beiträge.
Vielleicht magst du den Beitrag mit der Lösung nochmal verlinken.
Oder zitieren, wird ja nicht mehr als 1 Zeile sein.
Wilhelm M. schrieb:> Bei der trivialen Endlos-Schleife for(;;) {} kann der Compiler trivial> beweisen, dass die Schleife nicht terminiert, daher ist sie UB, und darf> entfernt werden.
Das ist aber schon eine interessante Auslegung. Er kann beweisen, dass
die Schleife nie verlassen wird, und deshalb kann er sie einfach
rauswerfen. Klar ist das bei UB nicht verboten, aber die Argumentation
wirkt trotzdem etwas komisch. Denn so macht der Code ja das exakte
Gegenteil von dem, was jemand, der diese Regel nicht kennt, erwarten
würde.
Jörg W. schrieb:> Wilhelm M. schrieb:>> Nein.>> main() ist besonders, dass es implizit 0 zurück gibt.>> OK, das war mir nicht bewusst.
Ist auch eine eher obskure Regel.
Jörg W. schrieb:> Korrekt, aber freestanding schaltet allerlei Optimierungen ab, die> Annahmen bezüglich der Standardbibliothek treffen.
Ich denke, es ist eher umgekehrt: Bei hosted ist dem Compiler explizit
erlaubt, die Annahme zu treffen, dass sich alle Standardfunktionen genau
so wie im Standard definiert verhalten und auf der Basis zu optimieren.
Ich wüsste aber nicht, dass es ihm bei freestanding verboten wäre,
Annahmen über mitgelieferte Funktionen zu treffen.
Hans H. schrieb:>> volatile long r;>> int main() {>> return collatz_conjecture(r);>> }>> Dein Beispiel ist UB, da auf r ohne Initialisierung zugegriffen wird.> Da kann der Compiler machen was er will.
Nein. Globale Variablen werden implizit mit 0 bzw.
default-initialisiert.
Wilhelm M. schrieb:> Also ein C++-Programm mit ISRs ist einfach nicht Standard-konform (s.o.> hatte ich schon geschrieben), damit erübrigt sich die Frage nach der> Schleife.
Das sehe ich anders. Was hab ich davon, zu sagen: "Ja, wegen der ISR ist
das Programm sowieso nicht konform, also ist auch egal, was bei der
Schleife passiert". Ich muss auf einem µC halt auch ISRs schreiben, und
die funktionieren auch wie gewünscht, die Schleife aber auf Grund dieser
Standard-Regel nicht.
Wilhelm M. schrieb:> Hans H. schrieb:>> und das Assemblerlisting zeigt daß er die Funktion so implementiert wie>> sie geschrieben steht.>> -O3 vergessen?
Tatsächlich, mit -O3 wird es dann auch im clang wegoptimiert,
kopfkratz...
Wilhelm M. schrieb:> Non-local with static storage
Hast Recht wird mit 0 initialisiert..., aber trotzdem konstant. Weil
ohne Speicheradresse ändert da auch das volatile nichts.
Hans H. schrieb:> Hast Recht wird mit 0 initialisiert..., aber trotzdem konstant.
Und? Ein volatile-Zugriff reicht aus, und das ist einer. Was drin steht
oder ob sich der Wert ändert, spielt keine Rolle.
> Weil ohne Speicheradresse ändert da auch das volatile nichts.
?
Wilhelm M. schrieb:>> Korrekt, aber freestanding schaltet allerlei Optimierungen ab, die>> Annahmen bezüglich der Standardbibliothek treffen.>> Wo steht das?
Annahmen hinsichtlich der Funktionalität der Standardbibliothek sind
halt einer der Punkte, der für ein hosted environment zutrifft.
"Any library facilities available to a freestanding program, other than
the
minimal set required by Clause 4, are implementation-defined."
Prinzipiell könnte es für Funktionen wie strlen() noch machbar sein,
diese bei einem konstanten String zu optimieren (Clause 4 würde das
meiner Meinung nach gestatten), aber in der Praxis passiert es nicht.
Compiliere einfach mal mit dem Compiler deiner Wahl mit -ffreestanding
und -fhosted:
1
#include<string.h>
2
3
intlen_of_foo(void){
4
returnstrlen("foo");
5
}
> Was hat das mit main() zu tun?
Dass main() in einem freestanding environment einfach gar nicht
definiert wird (und nicht einmal existieren muss), während es in einem
hosted environment halt die beiden genannten Prototypen mit Rückkehrwert
"int" haben soll (oder eben "implementation-defined").
Jörg W. schrieb:> Wilhelm M. schrieb:>>> Korrekt, aber freestanding schaltet allerlei Optimierungen ab, die>>> Annahmen bezüglich der Standardbibliothek treffen.>>>> Wo steht das?>> Annahmen hinsichtlich der Funktionalität der Standardbibliothek sind> halt einer der Punkte, der für ein hosted environment zutrifft.
Verstehe ich nicht, etwas verworren.
Alle Funktionen, die im Set der verpflichtenden Funktionen der
Freestanding Variante vorhanden sein müssen, müssen wie beschreiben
arbeiten.
Allerdings: <cstring> gehört gar nicht zum Freestanding set.
> "Any library facilities available to a freestanding program, other than> the> minimal set required by Clause 4, are implementation-defined."
Genau, Du benutzt etwas, was nicht dazu gehört. Insofern muss sich der
GCC gar nicht darum kümmern und kann deswegen auch gar keine
(Frontend)-Optimierungen ausführen.
>> Was hat das mit main() zu tun?>> Dass main() in einem freestanding environment einfach gar nicht> definiert wird (und nicht einmal existieren muss), während es in einem> hosted environment halt die beiden genannten Prototypen mit Rückkehrwert> "int" haben soll (oder eben "implementation-defined").
Ja, siehe oben:
Wilhelm M. schrieb:> Und als freestanding muss es noch nicht mal main() sein.
Moin,
ich möchte ungern die gesellige Runde stören. Nur verstehe ich aktuell
gerade nicht warum etwas UB sein soll wenn die gelebte Praxis seit
Jahrzehnten es genauso programmiert.
int main()
{
while(1) bzw. for(;;)
{
... sinnvoller Code ...
}
}
Würde ja bedeuten das entweder der Standard völlig an der Praxis vorbei
lebt oder der C++ Compiler sich nicht an den Standard hält oder noch
anders. Sonst wären ja alle Programme für µC UB. Kann ja nicht sein. Das
meinte ich mit, ich falle vom Glauben ab. Aber keine Sorge ich bin nicht
gläubig.
Moin,
Mir schwirrt schon der Kopf. Da war ich jahrzehntelang ein glücklicher
und zufriedener Programmierer. Dann kamt ihr; ihr, die jetzt meine heile
Welt in Schutt und Asche gelegt habt und ich mich am Boden zerstört
vorfinde:-) was nu?
Am Anfang konnte man sich ja nur an die Herstellerhandbücher halten und
die schwiegen sich über die hier diskutierten Feinheiten völlig aus. Die
konzentrierten sich eher auf bewährte Programmierpraxis anstatt auf
graue Theorie in verstaubten Compiler und Sprachenstandards
herumzustöbern.
Abgesehen davon gelten im embedded Bereich andere Berücksichtigungen um
im uC Bereich praxisgerecht zu sein. Z.B. ein return für main() hat da
ja keinen Sinn. In Systemen mit BS, gefordert.
Es funktionierte ja immer wie vorgegeben. Ich befasse mich auschließlich
mit embedded. Ist es dies alles in 99% aller Anwendungsfälle wert?
Irgendwie sollte embedded praxisnahe sein.
Gerhard
Habe gerade mal den folgenden Code mit g++ (64bit Linux) und auch
avr-g++ übersetzt. Sowohl ›while‹ als auch (alternativ) ›for‹ erzeugen
übrigens präzise den gleichen Assembler-Code.
Norbert schrieb:> Habe gerade mal den folgenden Code mit g++ (64bit Linux) und auch> avr-g++
Weil der GCC das so macht. Es besteht keine Pflicht den Code mit UB zu
entfernen.
Wilhelm M. schrieb:> Weil der GCC das so macht. Es besteht keine Pflicht den Code mit UB zu> entfernen.
Aha, interessant. Eine nicht ganz unwichtige Information.
Das heißt andere C++ - Compiler könnten sämtliche ISRs ungefragt weg
optimieren, weil die ja wohl auch - wie weiter oben zu lesen - UB sind.
Ein - hmmm, sagen wir mal - interessanter Ansatz.
Wenn ihr im Rahmen der Diskussion schlussendlich feststellt, dass es
zwar theoretisch möglich ist, nicht-triviale C- oder C++-Programme zu
schreiben, die ausschliesslich perfekt definiert (und korrekt) arbeiten,
nicht aber praktisch, dann seid ihr schon dicht in der Realität
angekommen. ;-)
Norbert schrieb:> Wilhelm M. schrieb:>> Weil der GCC das so macht. Es besteht keine Pflicht den Code mit UB zu>> entfernen.>> Aha, interessant. Eine nicht ganz unwichtige Information.
UB ist Verhalten, für das der Standard absolut keinerlei Vorgaben macht.
Es gibt damit grundsätzlich keine Verpflichtung für den Compiler,
irgendetwas zu tun oder nicht zu tun.
> Das heißt andere C++ - Compiler könnten sämtliche ISRs ungefragt weg> optimieren, weil die ja wohl auch - wie weiter oben zu lesen - UB sind.
Oben ist ausdrücklich zu lesen, dass sie im Standard schlicht gar nicht
existieren. Die Compiler-Unterstützung dafür liegt also so oder so
außerhalb des Standards. Da ISRs oft keine ganz normalen Funktionen
sind, gibt's gar nicht erst einen Standard-Weg, sie überhaupt zu
definieren. Und wenn ein Compiler schon eine solche
nicht-Standard-Erweiterung anbietet, wird er das natürlich so tun, dass
sie auch brauchbar ist.
Wilhelm M. schrieb:> Veit D. schrieb:>>> int main()>> {>> while(1) bzw. for(;;)>> {>> ... sinnvoller Code ...>> }>> }>>> Das hängt stark davon ab, was ... sinnvoller Code ... ist.
Es müsste eher ... sinnloser Code ... heißen, denn sobald der Code
irgendeine reale Auswirkung hat, gilt das nicht mehr.
Rolf M. schrieb:> Und wenn ein Compiler schon eine solche> nicht-Standard-Erweiterung anbietet
Beim Cortex-M sind ISRs normale Funktionen ohne irgendwelche
Sonderlocken wie Nicht-Standard-Erweiterungen. Damit können die also
alle weg. ;-)
Wilhelm M. schrieb:> template<auto N>> auto length(const char (&a)[N]) {> return N - 1;> }
Ist aber nicht das selbe wie strlen.
length("1""\0""2""\0""3""\0\0"); // -> 6
strlen("1""\0""2""\0""3""\0\0"); // -> 1
Veit D. schrieb:> Nur verstehe ich aktuell gerade nicht warum etwas UB sein soll> wenn die gelebte Praxis seit Jahrzehnten es genauso programmiert.
Weil WG21 das so festgelegt hat und seither for(;;){} Undefined
Behaviour ist.
Was ich vermisse, ist dass der aktualisierte Sprachstandard sowas wie
Best Practices" nennt, wie das Verhalten des ehemals gültigen Codes mit
den aktualisierten Mitteln erreicht werden kann.
Und hier im Thread wird auch drumrum geredet; wie so oft. Es werden
einem Buzzwords oder Teile des Standards um die Ohren gehauen, aber wie
genau etwas umgesetzt werden kann... da wird gekniffen.
> int main()> {> while(1) bzw. for(;;)> {> ... sinnvoller Code ...> }> }>> Würde ja bedeuten das entweder der Standard völlig an der Praxis vorbei> lebt
Wäre nicht das erste mal, dass Bedürfnisse von Bare Metal Plattformen
ignoriert werden.
Früher[tm] wäre /* Empty Body */ unter "sinnvollen Code" gefallen, weil
es Anwendungen dafür gibt. Mit akltellem C++ ist es kein sinnvoller
Code mehr da UB.
Aber was soll man stattdessen nehmen wenn man den Effekt des alten
for(;;){} erreichen will?
* Lokale volatile Variable schreiben ist nicht das was ich wollen würde,
weil das teuer ist (Code-Verbrauch).
* __asm volarile ("":); erzeugt zwar kein Overhead, ist aber nicht
Portabel und kein Standard-C++.
oder der C++ Compiler sich nicht an den Standard hält oder noch
> anders. Sonst wären ja alle Programme für µC UB. Kann ja nicht sein. Das> meinte ich mit, ich falle vom Glauben ab. Aber keine Sorge ich bin nicht> gläubig.
(prx) A. K. schrieb:> Rolf M. schrieb:>> Und wenn ein Compiler schon eine solche>> nicht-Standard-Erweiterung anbietet>> Beim Cortex-M sind ISRs normale Funktionen ohne irgendwelche> Sonderlocken wie Nicht-Standard-Erweiterungen.
Wie werden sie dann aufgerufen? Auch wenn die ISR an sich einfach als
Standard-Funktion definiert werden muss, muss der Compiler trotzdem
irgendeine Erweiterung haben, damit sie beim Interrupt auch zur
Ausführung kommen. Ein Compiler, der sie dann wegoptimiert, wäre zwar in
der Hinsicht standardkonform, aber für µC-Entwicklung halt nicht zu
gebrauchen.
Johann L. schrieb:> * Lokale volatile Variable schreiben ist nicht das was ich wollen würde,> weil das teuer ist (Code-Verbrauch).
Typischerweise zwei zusätzliche Instruktionen. Wenn die nicht mehr in
den Flash passen, wirst du eh bald ein Problem haben.
Rolf M. schrieb:>> Beim Cortex-M sind ISRs normale Funktionen ohne irgendwelche>> Sonderlocken wie Nicht-Standard-Erweiterungen.>> Wie werden sie dann aufgerufen?
Über die Vektortabelle. Auch diese ist aber ein ganz normales C-Array,
das lediglich an einer bestimmten Stelle im Speicher stehen muss.
Cortex-M ist ja explizit so designt worden, dass man keine
Assembler-Magie mehr benötigt – wenngleich es manche Hersteller
bevorzugen, den Startup-Code immer noch in Assembler zu meißeln. Bei
Atmels SAMDxx etc. dagegen ist der Startup-Code in C.
Üblicherweise werden die Funktionen der Vektortabelle zwar jenseits des
Standards als "weak" deklariert, aber das dient lediglich der
Bequemlichkeit, dass man auf diese Weise mit einer vorgefertigten
Tabelle arbeiten kann und nicht jede Applikation ihre eigene selbst
bauen muss. Technisch könnte man auch alles "pure C" selbst schreiben.
Rolf M. schrieb:> Wie werden sie [ISRs] dann aufgerufen?
Zum Beispiel indem IRQ-Vektoren initialisiert werden. Dass IRQ-Vektoren
mehr oder weniger hart verdrahtet sind wie bei avr-gcc ist eher
unüblich. Eher üblich wäre, ne IRQ nen indirekten Sprung zu nem
Signal-Handler ausführen zu lassen. Und der Handler (bzw. dessen
Adresse) wird vir dessen Verwendung eben irgendwo eingetragen.
> Auch wenn die ISR an sich einfach als Standard-Funktion definiert> werden muss, muss der Compiler trotzdem irgendeine Erweiterung haben,> damit sie beim Interrupt auch zur Ausführung kommen.
Bordmittel reichen aus, z.B. Funktionsadresse irgendwo eintragen. Oder
<signal.h>.
> Johann L. schrieb:>> * Lokale volatile Variable schreiben ist nicht das was ich wollen würde,>> weil das teuer ist (Code-Verbrauch).>> Typischerweise zwei zusätzliche Instruktionen. Wenn die nicht mehr in> den Flash passen, wirst du eh bald ein Problem haben.
Es ist mehr. GCC legt auto volatile Variablen im Frame an, nicht in
Registern. Es muss also auch ein Frame allokiert werden und zusäzulich
ein Frame-Pointer (der nicht wegoptimiert werden kann).
...ok, bei avr-g++ sind's nur 4 Instruktionen mehr, ist jetzt nicht
super tragisch. Aber es ist einfach auch hässlich, nen Code hinschreiben
zu müssen der mehr macht als nix.
Johann L. schrieb:> Aber was soll man stattdessen nehmen wenn man den Effekt des alten> for(;;){} erreichen will?
Heutzutage will man Strom sparen, also muss man das der Hardware
irgendwie sagen. Und schon ist die Schleife nicht mehr leer.
Was uns zum nächsten Problem bringt :) Wenn man dafür kein Bit setzen
kann, braucht man einen Maschinenbefehl wie WFI. Was sagt der Standard
denn dazu?
Jörg W. schrieb:> Rolf M. schrieb:>>> Beim Cortex-M sind ISRs normale Funktionen ohne irgendwelche>>> Sonderlocken wie Nicht-Standard-Erweiterungen.>>>> Wie werden sie dann aufgerufen?>> Über die Vektortabelle. Auch diese ist aber ein ganz normales C-Array,> das lediglich an einer bestimmten Stelle im Speicher stehen muss.
Das meinte ich nicht. Der Aufruf wird initial nicht durch in C++
geschriebenen Code ausgelöst, sondern durch interne Hardware des µC. Und
damit liegt er außerhalb des Standards.
Johann L. schrieb:> Bordmittel reichen aus, z.B. Funktionsadresse irgendwo eintragen. Oder> <signal.h>.
Ein Standard-konformer Compiler kann von einem gewissen Codefluss
ausgehen. Und da ist es nicht vorgesehen, dass quasi aus dem Nichts
heraus mitten in der Ausführung spontan irgendeine Funktion aufgerufen
wird, obwohl an der Stelle im Code kein Funktionsaufruf steht.
>> Typischerweise zwei zusätzliche Instruktionen. Wenn die nicht mehr in>> den Flash passen, wirst du eh bald ein Problem haben.>> Es ist mehr. GCC legt auto volatile Variablen im Frame an, nicht in> Registern. Es muss also auch ein Frame allokiert werden und zusäzulich> ein Frame-Pointer (der nicht wegoptimiert werden kann).
Dann einfach static machen. Braucht dann halt noch ein Byte im RAM,
dafür keinen Stackframe.
> ...ok, bei avr-g++ sind's nur 4 Instruktionen mehr, ist jetzt nicht> super tragisch.
Ich habe ein ldi vor und ein std in der Schleife gesehen, zumindest bei
-Os. Natürlich habe ich aber nicht int, sondern uint8_t genommen. Bei
-O3 scheint er lustigerweise ein loop-Unrolling zu machen, aber nur wenn
die Variable nicht static ist.
Mit -O3:
1
main:
2
push r28
3
push r29
4
push __zero_reg__
5
in r28,__SP_L__
6
in r29,__SP_H__
7
/* prologue: function */
8
/* frame size = 1 */
9
/* stack size = 3 */
10
.L__stack_usage = 3
11
ldi r24,lo8(42)
12
.L2:
13
std Y+1,r24
14
std Y+1,r24
15
rjmp .L2
Mit -Os:
1
main:
2
push r28
3
push r29
4
push __zero_reg__
5
in r28,__SP_L__
6
in r29,__SP_H__
7
/* prologue: function */
8
/* frame size = 1 */
9
/* stack size = 3 */
10
.L__stack_usage = 3
11
ldi r24,lo8(42)
12
.L2:
13
std Y+1,r24
14
rjmp .L2
> Aber es ist einfach auch hässlich, nen Code hinschreiben zu müssen der> mehr macht als nix.
Es ist auch schon hässlich, Code hinschreiben zu müssen, dessen einzige
Aufgabe es ist, eigentlich nichts zu machen.
Bevor hier manche Schnappatmung bekommen ...
1) Das in C++ for(;;) {} UB ist, heißt nicht, dass dort unbrauchbarer
Code heraus kommen muss.
2) GCC zeigt, dass man dies offensichtlich erkannt hat, und wohl hier
einfach die C-Variante übernimmt. Wobei es wohl anders ist, dass hier
einfach das gleich Backend/Middlend mit derselben Formulierung in der
RTL gefüttert wird.
3) Was clang++ da macht, ist zwar "legal" und sicher ein schönes
Schulbeispiel für die Auswirkungen von UB. Allerdings verletzt dies
eklatant die Regel des least-astonischments.
4) Die WG14 / WG21 arbeiten dran, diese verkorkste Formulierung im C++
Standard zu verbessern.
Allerdings würde ich mich mal wirklich dafür interessieren, in welchem
Projekt (mehr als Küchentisch-Hobby) diese Schleife so vorkommt.
Daniel A. schrieb:> Wilhelm M. schrieb:>> template<auto N>>> auto length(const char (&a)[N]) {>> return N - 1;>> }>> Ist aber nicht das selbe wie strlen.> length("1""\0""2""\0""3""\0\0"); // -> 6> strlen("1""\0""2""\0""3""\0\0"); // -> 1
Wilhelm M. schrieb:> Allerdings würde ich mich mal wirklich dafür interessieren, in welchem> Projekt (mehr als Küchentisch-Hobby) diese Schleife so vorkommt.
Und außerdem ist es vollkommen egal, mit welchem Unsinn die CPU in der
Endlos-Schleife Ihre Zeit verbringt.
Also wenn Euch
1
while(true){
2
sleep();
3
}
nicht passt, dann nehmt
1
while(true){
2
noop();
3
}
Und das noop() könnt ihr nach Eurem Gusto ausgestalten:
1
namespace{
2
volatileuint8_tdummy;
3
voidnoop(){
4
(void)dummy;
5
}
6
}
Dadurch wird die Latenz bis zur ISR auch nicht schlechter.
Wilhelm M. schrieb:> Bevor hier manche Schnappatmung bekommen ...>> 1) Das in C++ for(;;) {} UB ist, heißt nicht, dass dort unbrauchbarer> Code heraus kommen muss.
Doch, der Code ist unbrauchbar weil man sich nicht darauf verlassen
kann.
Oder verwendest du UB in deinen Projekten, und kontrollierst nach jedem
Compilerlauf, ob das generierte Assembly noch deinen Wünschen
entspricht?
> 2) GCC zeigt, dass man dies offensichtlich erkannt hat,
Es zeigt garnix. Insbesondere zeigt es nicht, dass der Code verwendbar
wäre (da UB). Es scheint auch kein Schalter (wie etwa für Signed
Overflow) zu geben, der die alte Semantik von for(;;) herstellt.
> Allerdings würde ich mich mal wirklich dafür interessieren, in welchem> Projekt (mehr als Küchentisch-Hobby) diese Schleife so vorkommt.
Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog.
Phase 1: Watchdog wird konfiguriert und aktiviert.
Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen
Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder
zumindest mehrere µs dauern.
Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am
Ende von main, nach Konfiguration aller IRQs, steht dann eine leere
Endlosschleife.
Johann L. schrieb:> Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog.>> Phase 1: Watchdog wird konfiguriert und aktiviert.>> Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen> Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder> zumindest mehrere µs dauern.
Und wann macht das Ding dann etwas? Immer nur zwischen Phase 1 und 2?
> Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am> Ende von main, nach Konfiguration aller IRQs, steht dann eine leere> Endlosschleife.
Das muss man aber so nicht machen. Mann kann das auch anders lösen.
Deswegen ist das kein Argument.
Wilhelm M. schrieb:> Und wann macht das Ding dann etwas? Immer nur zwischen Phase 1 und 2?
Es geht darum, gezielt einen Hardware-Reset auszulösen auf Plattformen,
die das nicht direkt können (bpsw. AVR). Nachdem man den Wachhund
gezündet hat, soll natürlich einfach mal nichts mehr passieren, bis er
dann zuschlägt. Das "nichts mehr" macht man in einer harten
Endlosschleife.
Anderer realer Fall: MCU im Fehlerfall (bspw. bei einem abort())
anhalten. Wenn man mit dem Debugger dran sitzt, kann man dann an der
Stelle unterbrechen und versuchen nachzuvollziehen, wie es zum Fehler
gekommen ist. Auch das braucht einfach eine harte Endlosschleife.
Ähnlich, wenn man auf einer MCU aus main() zurückkehrt.
Wilhelm M. schrieb:> Johann L. schrieb:>> Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog.>>>> Phase 1: Watchdog wird konfiguriert und aktiviert.>>>> Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen>> Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder>> zumindest mehrere µs dauern.>> Und wann macht das Ding dann etwas?
In Phase 1 macht es etwas: Initialisierung etc.
In Phase 2 macht es etwas: JMP auf sich selbst bis die Zeit zum
Watchdog-Reset verstrichen ist.
Falls du nicht weißt was'n Watchdog ist:
https://de.wikipedia.org/wiki/Watchdog>> Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am>> Ende von main, nach Konfiguration aller IRQs, steht dann eine leere>> Endlosschleife.>> Das muss man aber so nicht machen.
Na das ist man ein Argument. Bravo!
Jörg W. schrieb:> Wilhelm M. schrieb:>> Und wann macht das Ding dann etwas? Immer nur zwischen Phase 1 und 2?>> Es geht darum, gezielt einen Hardware-Reset auszulösen auf Plattformen,> die das nicht direkt können (bpsw. AVR). Nachdem man den Wachhund> gezündet hat, soll natürlich einfach mal nichts mehr passieren, bis er> dann zuschlägt. Das "nichts mehr" macht man in einer harten> Endlosschleife.
Mir ist schon klar, was ein WatchDog erreichen soll. Nur wo "sitzt" in
dem Beispiel die Applikation?
> Anderer realer Fall: MCU im Fehlerfall (bspw. bei einem abort())> anhalten. Wenn man mit dem Debugger dran sitzt, kann man dann an der> Stelle unterbrechen und versuchen nachzuvollziehen, wie es zum Fehler> gekommen ist. Auch das braucht einfach eine harte Endlosschleife.> Ähnlich, wenn man auf einer MCU aus main() zurückkehrt.
In diesem Fall kommt es aber so gar nicht darauf an, mit welcher
Frequenz die Loop durchlaufen wird. Ggf. wird man darin eh irgend etwas
tun, ggf. sogar ein Pin wackeln. Also hier muss man kein UB haben.
Deswegen ist das auch kein Argument.
Johann L. schrieb:> Wilhelm M. schrieb:>> Johann L. schrieb:>>> Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog.>>>>>> Phase 1: Watchdog wird konfiguriert und aktiviert.>>>>>> Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen>>> Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder>>> zumindest mehrere µs dauern.>>>> Und wann macht das Ding dann etwas?>> In Phase 1 macht es etwas: Initialisierung etc.>> In Phase 2 macht es etwas: JMP auf sich selbst bis die Zeit zum> Watchdog-Reset verstrichen ist.
Wenn das Ding nur auf den WatchDog wartet, ohne da jemals eine LED
angeht, dann kann ich auch einfach einen ohmschen Widerstand nehmen, um
den Strom zu verbrauchen.
>>> Beispiel 2: Eine Applikation, die all ihre Aufgaben in ISRs erledigt. Am>>> Ende von main, nach Konfiguration aller IRQs, steht dann eine leere>>> Endlosschleife.>>>> Das muss man aber so nicht machen.>> Na das ist man ein Argument. Bravo!
Du stehst also auf dem Standpunkt: ich WILL aber unbedingt so eine
Endlos-Schleife in C++, und ich weiß aber, dass das UB ist, und ich WILL
aber, das es trotzdem geht. Mmh, hört sich an wie Vorschulalter ...
Wilhelm M. schrieb:> Johann L. schrieb:>> Wilhelm M. schrieb:>>> Johann L. schrieb:>>>> Ein Beispiel hat Andreas schon genannt: Hardware-Reset mittels Watchdog.>>>>>>>> Phase 1: Watchdog wird konfiguriert und aktiviert.>>>>>>>> Phase 2: Es wird gewartet, bis der Watchdog zuschlägt und einen>>>> Hardware-Reset triggert. Das kann je nach Hardware ein paar ms oder>>>> zumindest mehrere µs dauern.>>>>>> Und wann macht das Ding dann etwas?>>>> In Phase 1 macht es etwas: Initialisierung etc.>>>> In Phase 2 macht es etwas: JMP auf sich selbst bis die Zeit zum>> Watchdog-Reset verstrichen ist.>> Wenn das Ding nur auf den WatchDog wartet, ohne da jemals eine LED> angeht, dann kann ich auch einfach einen ohmschen Widerstand nehmen, um> den Strom zu verbrauchen.
Ach komm, gib dich mal nicht dümmer als du bist. Du verstehst doch sehr
wohl wozu das gut ist. Und ja, die Applikation macht mehr als nur
einen Reset. Der Reset wird nur bei bestimmten Vorbedingungen
gebraucht.
Denkbare Anwendung wäre ein Bootloader, der nach Aktualisiserung der
Anwendung diese anspringt. Ein Hardware-Reset resettet die ganze
Hardware, was hier gewünscht ist.
> so eine Endlos-Schleife in C++, und ich weiß aber, dass das UB ist,> und ich WILL aber, das es trotzdem geht.
Ja. Weil in neueren C++ Versionsn for(;;); UB ist, möchte ich wissen,
welches Konstrukt der empfohlene, portable Weg ist, was alte Verhalten
zu erreichen.
Ist das so viel verlangt?
Johann L. schrieb:> Ja. Weil in neueren C++ Versionsn for(;;); UB ist, möchte ich wissen,> welches Konstrukt der empfohlene, portable Weg ist, was alte Verhalten
Das war <= C++03 (vor 20 Jahren)
> zu erreichen.
Nochmal: for(;;){} ist UB. Punkt.
> Ist das so viel verlangt?
Das habe ich nun schon x-mal geschrieben, welche Alternativen zur
Verfügung stehen. Und das sind dann welche, die die Latenz für die ISR
gar nicht beeinflussen. Daher: nimm sie, oder lass es sein.
Wilhelm M. schrieb:> Johann L. schrieb:>> Ja. Weil in neueren C++ Versionsn for(;;); UB ist, möchte ich wissen,>> welches Konstrukt der empfohlene, portable Weg ist, was alte Verhalten>> Das war <= C++03 (vor 20 Jahren)>>> zu erreichen.>> Nochmal: for(;;){} ist UB. Punkt.
Klar. Und genau deshalb frage ich ja nach einem ERSATZ.
> Das habe ich nun schon x-mal geschrieben, welche Alternativen zur> Verfügung stehen.
Bisher habe ich zumindest in diesem Thread von dir keine einzige
Alternative gefunden. Wortreiche Umschreibungen und Characterisierungen
ja, aber wie lautet denn nun der magische Code?
Hallo,
ich muss zugeben mir ergeht es aktuell wir Gerhard. Der Thread hat mich
vollkommen durcheinander gebracht. Gewohnte Fachbegriffe haben hier eine
andere Bedeutung erlangt. Ich komme einfach nicht mehr mit. Ich gebe es
auf. Ich programmiere weiter wie immer und hoffe das alles funktioniert.
Ich muss mich darauf verlassen das der gcc keinen ungewohnten Mist
macht. Ich danke allen die Antworten auf meine Fragen gegeben haben,
auch wenn ich diese im Zusammenhang hier nur noch teilweise verstehe und
einsortieren kann. Weitere Nachfragen würden in einer weiteren
nebenläufigen Endlosschleife enden. Das möchte ich niemanden zumuten.
Ich melde mich aus dem Thread ab.
Wilhelm M. schrieb:> Johann L. schrieb:>> Bisher habe ich zumindest in diesem Thread von dir keine einzige>> Alternative gefunden. Wortreiche Umschreibungen und Characterisierungen>> ja, aber wie lautet denn nun der magische Code?>> z.B.:>> Beitrag "Re: for(;;){} Schleife">> oder>> Beitrag "Re: for(;;){} Schleife"
C++ definiert sleep() und noop() ?
Nicht-portable Lösungen sind ja naheliegend, wie __asm volatile ("":);
für g++.
Aber das ist offenschtlich NICHT portabel.
Johann L. schrieb:> Wilhelm M. schrieb:>> Johann L. schrieb:>>> Bisher habe ich zumindest in diesem Thread von dir keine einzige>>> Alternative gefunden. Wortreiche Umschreibungen und Characterisierungen>>> ja, aber wie lautet denn nun der magische Code?>>>> z.B.:>>>> Beitrag "Re: for(;;){} Schleife">>>> oder>>>> Beitrag "Re: for(;;){} Schleife">> C++ definiert sleep() und noop() ?
Das spielt schon in dem Moment keine Rolle mehr, wo Du ISRs einsetzt.
Denn die sind auch nicht konform.
>> Nicht-portable Lösungen sind ja naheliegend, wie __asm volatile ("":);> für g++.>> Aber das ist offenschtlich NICHT portabel.
Du argumentierst doch im Kreis: einerseits willst Du ISRs oder
Exception-Handler oder WDT einsetzen, die nicht portabel sind, und
andererseits beschwerst Du Dich über sleep() und noop(), was nicht
portabel sei?
Wenn Du komplett auf nicht-potable Sachen wie ISRs, sleep(), noop(),
etc. verzichtest, dann hast Du ein Programm ohne sichtbaren Effekt. Das
ist sinnlos, und nichts anderes sagt diese Regel aus C++.
Wie gesagt, eine leere Endlosschleife (natürlich ein nicht-UB Ersatz
dafür) KANN sinnvoll sein, egal ober der Rest des Codes ISRs oder was
auch immer verwendet oder nicht.
Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code,
der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden.
Ich denke auch nicht, dass du noch mit einer Lösung um die Ecke kommst.
Johann L. schrieb:> Wie gesagt, eine leere Endlosschleife (natürlich ein nicht-UB Ersatz> dafür) KANN sinnvoll sein, egal ober der Rest des Codes ISRs oder was> auch immer verwendet oder nicht.
Beispiel? Und - um Deine Worte zu gebrauchen - keine wortreichen
Umschreibungen.
> Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code,> der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden.
Tut er bereits durch die ISRs. Daher darfst Du ruhig Dein asm("")
einsetzen, das zwar implementation-defined ist, aber auf wohl den
meisten Compilers tut.
> Ich denke auch nicht, dass du noch mit einer Lösung um die Ecke kommst.
Die verlinkte noop() Variante ist komplett konform (man könnte auf das
eine Byte auch noch verzichten).
Wilhelm M. schrieb:> Johann L. schrieb:>> Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code,>> der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden.>> Tut er bereits durch die ISRs.
Der Unterschied ist aber, dass die für ISRs erforderlichen Mittel von
der Implementation zur Verfügung gestellt und garantiert werden.
Von daher sind das alles Strohmann-Nebelkerzen deinerseits.
> Die verlinkte noop() Variante ist komplett konform (man könnte auf das> eine Byte auch noch verzichten).
Ok hatte die Definition übersehen.
Wobei es hier auch schon mal ne ewige endlos-Diskussion darüber gab, ob
(void) var; for eine volatile Variable noch den neueren Standards
entsprechen die auch an volatile rumgeschraubt haben.
Und wie man das 1 Byte einsparen könnte, sehe ich auch nicht.
Johann L. schrieb:> Wilhelm M. schrieb:>> Johann L. schrieb:>>> Nach deiner Lesart sind ISRs nicht sprachkonform, und daher kann Code,>>> der ISRs verwendet, beliebige nicht-konfirme Konstrukte verwenden.>>>> Tut er bereits durch die ISRs.>> Der Unterschied ist aber, dass die für ISRs erforderlichen Mittel von> der Implementation zur Verfügung gestellt und garantiert werden.
Dann kannst Du genau diese "Mittel" auch in der trivialen Endlos-Loop
verwenden, also z.B. asm("") der Implementierung.
> Von daher sind das alles Strohmann-Nebelkerzen deinerseits.
Nein, ich habe Dir das jetzt mehrmals schlüssig dargelegt.
Wie gesagt:
Wilhelm M. schrieb:> Du stehst also auf dem Standpunkt: ich WILL aber unbedingt so eine> Endlos-Schleife in C++, und ich weiß aber, dass das UB ist, und ich WILL> aber, das es trotzdem geht. Mmh, hört sich an wie Vorschulalter ...>> Die verlinkte noop() Variante ist komplett konform (man könnte auf das>> eine Byte auch noch verzichten).>> Ok hatte die Definition übersehen.
Also, erst lesen, dann meckern.
> Wobei es hier auch schon mal ne ewige endlos-Diskussion darüber gab, ob> (void) var; for eine volatile Variable noch den neueren Standards> entsprechen die auch an volatile rumgeschraubt haben.
Es gibt nur die Warnung (gcc), dass die Variable tatsächlich nicht
benutzt wurde. Das ist auch gut so. Denn wäre dass ein SFR, wäre es
bestimmt ein Fehler.
> Und wie man das 1 Byte einsparen könnte, sehe ich auch nicht.
Ich gehe davon aus, das der fragliche Code sicher irgendwo (lokal in
main, global, ...) ein beliebiges Objekt definiert, was man
volatile-referenzieren kann.
Diese Thread hat sich echt interessant entwickelt. Danke für die vielen
Aspekte.
Die Beispiele von Johann hatte ich schon öfters in realem Code. Eure
Diskussion aktuell geht aber meiner Meinung nach am wesentlichen vorbei:
Vielen Entwicklern – nicht nur Anfängern – sind die Konstrukte, die
Undefined Behavior erzeugen nicht bewusst, sei es, dass sie sich nie
damit beschäftigt haben, sei es, dass sie es vergessen haben.
Ich habe mit Softwareentwicklern mal ein Quiz veranstaltet. Es war
erschreckend wie viele Programmierer UB Fälle nicht erkannt haben.
Wenn C++(03) eine for(;;); Schleife wegen UB rausoptimiert, ohne eine
Warnung zu generieren, ist das die schlechteste Vorgehensweise. Gerade
dann, wenn es "ähnlichen" C Code gibt, der so etwas nicht raus
optimiert.
Es gilt eigentlich die Goldene Regel: Kenne Deine Werkzeuge!
Die Praxis zeigt: der Mensch macht Fehler, ist vergesslich und macht
Annahmen, die nicht stimmen.
In diesem Kontext sollte ein Compiler eigentlich auf UB hinweisen. Tut
er hier nicht, und das ist IMHO ein Problem.
Warum C++03 damals die Schleife als UB angesehen hat, hat mich immer
gewundert.
Wenn die (embedded) Praxis viele Beispiele hat, macht es keinen Sinn das
Verhalten zu ändern.
Moin,
Ich finde diese UB Möglichkeiten und Unsicherheiten nicht gerade sehr
erbauend. Ich kann nicht beurteilen, inwiefern moderne Tools anderer
Produkte sich daranhalten, die sich an die neuesten Standards halten.
Fakt ist, daß alle meine älteren Tools dieses speziell aufgebrachten
Problem nicht haben und diese Konstrukte, wie traditionell erwartet,
richtig funktionieren. Abgesehen davon, merkt man ja beim Testen sofort,
ob der Compiler sich solche Freiheiten erlaubt hat.
Man gewinnt ja über die Jahre hinaus viele Erfahrungen mit den
Werkzeugen mit denen man zu tun hat und kennt die besonderen Probleme
und vermeidet die "bösen" Konstrukte.
Ich befasse mich auch mit einigen anderen uC anderer Hersteller und die
Werkzeuge sind auch nicht mehr die Jüngsten. Jedenfalls wären mir diese
"Freiheiten" schon längst beim Testen aufgefallen. Noch nie hatte ich
mit den hier diskutierten Schleifenkonstrukten jemals ein Problem und
mir hat noch kein Compiler eine Test Watchdog Trigger Endlosschleife
wegoptimiert. Das wäre beim Testen sofort aufgefallen.
Inwieweit UB ein praktisches Problem ist oder eher ein Akademisches,
kann ich nicht wirklich beurteilen. Ausschlaggebend für mich ist, daß
die Sprache anhand der bereitgestellten Dokus, so wie dort beschrieben,
richtig funktioniert. Früher schien das zu genügen um produktiv in der
Praxis wirken und bestehen zu können.
Wie ist es in der UNI? Lernt man dort hauptsächlich die Sprachen und
deren Anwendung, oder studiert man extensiv Compiler Standard Dokus?
Sicher, ab und zu muß man sie bei der Fehlersuche konsultieren, aber das
sollte nur selten notwendig sein.
Hätte es wirklich viel Sinn, alle diese Compiler Standard
Schrulligkeiten lernen und im Kopf behalten zu müssen? Ich glaube, nein.
Es kommt halt letzen Endes darauf an, wie zuverlässig das Gesamtprodukt
sein muß, um diese Unsicherheiten überprüfen zu wollen.
Letzten Endes kommt es auf ausreichend gutes und komplettes Testen der
Anwendung an.
Letztlich bin ich also der Meinung, daß Eure ganze Diskussion fast
vollkommen akademisch ist und in der Praxis nur unter besonderen
Umständen Gewicht hat, wenn man genug Praxis Erfahrung mit den
Werkzeugen hat.
Das größte Problem mit C++ ist, daß es viel zu komplex und "fancy"
geworden ist und dieser Trend fortgehend weitergeht. Viele Eigenschaften
sind so implizit und versteckt, daß nur noch ein ausgedehntes Studium
darüber Klarheit beschafft.
In klassischen C, da nur ein Mittelding zwischen ASM und Hochsprachen
sein wollte, waren viel klarere Verhältnisse. Der Trouble mit C++ ist,
daß man es heute als "Mädchen für alles" hochgezogen hat und derart
komplex geworden ist, daß nur noch hartgesottene Spezialisten, die
täglich ihr Brot damit verdienen, sich damit ausreichend auskennen. Zum
gelegentlichen Programmieren sollte man die esoterischen Besonderheiten
der Sprache, meiner Meinung nach eher vermeiden wenn sie nicht
ausdrücklich extrem nützlich sind, und lieber mit Grundfunktionalität
jonglieren.
Mir ist aufgefallen, daß ältere traditionelle Sprachen großteils aus
ihrem Syntax verständlich waren. Eine Fortran oder Pascal Quelle konnte
man mit wenig Recherche verstehen, die heutigen Sprachen sind ohne
Studium fast vollkommen unverständlich. Der Syntax gibt beim Lesen nicht
länger Aufschluss auf die gemeinte Funktionalität. Nur ausführliches
Wissen dieser Konstrukte und zugängliche Referenzdokumentation gibt noch
Aufschluss. Das ist der Preis des Fortschritts, vermute uch.
Aus meiner Sicht machte ich die Erfahrung, daß ich C Code meist total
verständlich finde, bei C++ andauernd nachschlagen muß was im Einzeln
gemeint ist und die Terminologie nicht unbedingt immer ausreichend
verständlich ist. Ja, Klassen und Objekte können ja recht nützlich und
bequem sein. Aber für viele embedded Anwendungen mit Ressourcen
begrenzten uC eigentlich doch nicht wirklich notwendig. Bei der
Fehlersuche kann da schon viel zu viel versteckt sein. Speziell bei
fremden Bibliotheken, wo man dann auch jene durchgehen muß.
Sind halt meine Ansichten, aber die, viele von Euch wahrscheinlich
lächeln werden. Aber nicht jeder steckt in Euren Schuhen. Und da ich
mich viel mit HW Design befasse, programmiere ich eben nicht den ganzen
Tag, täglich. Es ist ja gut, daß sich jemand (ihr) über UB Gedanken und
deren möglichen Auswirkungen macht.
Vg,
Gerhard
Klaus H. schrieb:> Warum C++03 damals die Schleife als UB angesehen hat, hat mich immer> gewundert.
Kann eigentlich nicht sein, denn diese "Formulierung" wurde erst mit
C++11 bzw. C11 eingeführt zusammen mit der Definition des Memory-Models.
Das Memory-Model wiederum war notwendig, damit gerade die nebenläufigen
Konstrukte eine definiterte Semantik bekommen.
Diese "Problem", was wir hier diskutieren, ist m.E. die Diskussion um
die leere Menge. Denn in der Praxis leben wir mit sehr vielen,
nicht-standardisierten Erweiterungen im C++-Compiler (auch im
C-Compiler). Schließlich haben wir uns auch daran gewöhnt, nicht
standard-konforme ISRs, asm()-Konstrukte, etc. in unseren MCU-Code
einzubauen. Deswegen habe ich wiederholt versucht darzustellen, dass das
Problem in der Praxis gar nicht existiert. Sei es, weil die leere,
triviale Endlos-Schleife ein Spezialfall darstellt, oder Werkzeuge wie
GCC ein konsistentes Verhalten im Sinne des least-astonishments zeigen.
Trotzdem muss man bei den Sprachen C und C++ das Konzept des UB einfach
kennen, denn es ist ein Grundprinzip dieser beiden. Wer das ignoriert,
hat schlicht die Sprache nicht verstanden.
Und ich möchte nicht wissen, in wie vielen Fällen auch heute noch
type-punning via raw-unions in C++ gemacht wird. Das ist zwar ganz klar
UB, jedoch wird es im g++ genauso wie im gcc, also im C-Mode behandelt,
wo es eben kein UB ist. Das ist auch gut so, verhindert es doch
allzugroße Unfälle. Gleichzeitig ist es aber auch schlecht, weil man auf
den Fehler nicht hingewiesen wird, solang man keine Analyse-Tools
verwendet, was die wenigsten hier wohl machen werden.
Daran zeigt sich eben, dass C keine Untermenge von C++ ist, sondern eine
eigene Sprache.
Deswegen: diese Diskussion hier mag akademisch erscheinen bzw. auch
sein, denn - wie gesagt - bin ich der Meinung, dass dies ein Spezialfall
ist und wir in der Praxis damit in Reinform gar nicht in Berührung
kommen, weil jedes MCU-Programm neben dem Standard liegt. Aber diese
Diskussion soll ein Hinweis darauf sein, dass man mit dem Konzept UB
umgehen muss: egal, ob Loops, raw-unions, integer-overflow,
uninitialized variables, off-object pointer dereference, .....
Wilhelm M. schrieb:> Kann eigentlich nicht sein, denn diese "Formulierung" wurde erst mit> C++11 bzw. C11 eingeführt zusammen mit der Definition des Memory-Models.> Das Memory-Model wiederum war notwendig, damit gerade die nebenläufigen> Konstrukte eine definiterte Semantik bekommen.
Ups, sorry. Hast recht.
Aber es ändert nichts daran, dass das Konstrukt for(;;); schon Jahre
lang im emedded Bereich eingesetzt wurde. Deine Beispiel zeigen ja
schön, dass die meisten Compiler es trotzdem wie früher umgesetzt haben.
Ich mag clang, aber dieses Verhalten ohne Warnung halte ich für
gefährlich.
Wenn der Code beim Build jeweils vollständig getestet wird, vielleicht
kein Problem. In der Praxis sehe ich aber immer wieder Firmware, die
nach dem Motto „wir haben es zwar nicht dokumentiert, aber
Entwicklertests wurden gemacht“ getestet wurden.
Wilhelm M. schrieb:> Und ich möchte nicht wissen, in wie vielen Fällen auch heute noch> type-punning via raw-unions in C++ gemacht wird
Jepp, viel zuviel.
Wilhelm M. schrieb:> Aber diese Diskussion soll ein Hinweis darauf sein, dass man mit dem Konzept UB> umgehen muss: egal, ob Loops, raw-unions, integer-overflow,> uninitialized variables, off-object pointer dereference, .....
Volle Zustimmung. Und das Betrifft natürlich C++ und auch C.
Moin,
Es würde mich interessieren, welche Berücksichtigungen für den embedded
Bereich gemacht werden.
Evaluiert der Compiler Quellen für Linux Anwendungen genauso wie für
z.B. für den AVR? Inwieweit wird auf die Besonderheiten der uC Rücksicht
genommen?
Das zu wissen, würde einen gewissen Anhaltspunkt geben.
Was mich an diesem Thema stört, ist dass viele Leute einschließlich
mich, vor einigen Jahrzehnten mit C Anwendung angefangen haben und die
damaligen (kommerziellen) Werkzeuge nur den Sprachengebrauch ohne
hintergründige Theorie dokumentierten. Da wurden niemals
Konformitätsreferenzen gegeben. Es gab Beispiele und das wars auch. Der
Entwickler musste dann eben mit der Zeit seine eigenen Erfahrungen
machen.
Und, mit Verlaub, jetzt seid ihr da und taucht mächtig in den Morass der
UB ein, den nur ein Experte wirklich beurteilen kann. Hat sich
Entwicklung nun in 2023 so geändert und hochgeschraubt, daß es ohne Euer
(Fach) Wissen in der Praxis nicht mehr geht? Ich will einfach nicht
glauben, daß die Ingenieure in den zahlreichen Betrieben in den
Anfangsjahren auf Eurem Niveau sein konnten.
Abgesehen davon, wer versteht schon gleich die Erklärungen über jedes
Detail. Zum Teil verstehe ich da auch nur Bahnhof. Diese Fachsprache zu
verstehen ist keine Kleinigkeit.
Wo ist da der Mittelweg? Bitte seht es nicht nur von Eurem Standpunkt
aus. Es gibt bestimmt noch viele embedded Entwickler die das eher mehr
praxisbezogen angehen und auch nicht den Sprachenexpertenfachbezug
haben, aber sonst für viele Anwendungen ordentlich programmieren können.
Und wo gibt es verständliche Dokus, die etwas breiter verständlich sind?
Die Compiler Referenzunterlagen sind leider oft nur schwer verdaulich.
Auch im Web, wie z.B. bei Stack Overflow, versteht man auch nicht immer
gleich alles.
Man bekommt von dieser Diskussion wirklich den Eindruck, wer nicht auf
Eurem Niveau ist, in der Industrie nicht mehr die geringste Chance haben
zu können. Bitte seht das nicht als persönlichen Angriff bzw. Kritik,
aber überm Zaun ist die Welt vielleicht doch etwas diverser.
Gerhard
Gerhard O. schrieb:> Inwieweit wird auf die Besonderheiten der uC Rücksicht genommen?
Gar nicht, denn der größte Teil der Optimierungen passiert weit oberhalb
des Niveaus der konkreten Maschine. Nur so profitieren aber eben auch
"tier 3"-Plattformen trotzdem noch von vielen Optimierungen, die
vorrangig für die "tier 1"-Plattformen entwickelt und getestet werden.
Gerhard O. schrieb:> Evaluiert der Compiler Quellen für Linux Anwendungen genauso wie für> z.B. für den AVR? Inwieweit wird auf die Besonderheiten der uC Rücksicht> genommen?Jörg W. schrieb:> Gar nicht, denn der größte Teil der Optimierungen passiert weit oberhalb> des Niveaus der konkreten Maschine.
Jein, für uC kann man (sollte man? wird man normalerweise?)
-ffreestanding angeben. Das gibt es mindestens seit C99. Damit bekommt
der Programmierer ein paar Freiheiten (z.B. main, newlib-nano) und muss
dafür auf ein paar Optimierungen verzichten, weil es praktisch keine
Standard-Bibliotheken gibt:
Jörg W. schrieb:> Annahmen hinsichtlich der Funktionalität der Standardbibliothek sind> halt einer der Punkte, der für ein hosted environment zutrifft.>> "Any library facilities available to a freestanding program, other> than the minimal set required by Clause 4, are implementation-defined.">> Prinzipiell könnte es für Funktionen wie strlen() noch machbar sein,> diese bei einem konstanten String zu optimieren (Clause 4 würde das> meiner Meinung nach gestatten), aber in der Praxis passiert es nicht.
Bisher wurden in diesem minimal set nur Konstanten definiert und Dinge
wie stdarg, die fest im Compiler eingebaut sein müssen. Mit string.h
kommen bei C23 zum ersten Mal echte Bibliotheksfunktionen dazu. Bisher
musste man für uC-Programme nur den gcc installieren, keine libc. Damit
das so bleibt, müsste der gcc die string-Funktionen mitliefern. Es ist
ja nicht sicher, ob z.B. die newlib-nano 100% konform ist.
Bauform B. schrieb:>> Gar nicht, denn der größte Teil der Optimierungen passiert weit oberhalb>> des Niveaus der konkreten Maschine.>> Jein, für uC kann man (sollte man? wird man normalerweise?)> -ffreestanding angeben.
Wie schon dargelegt, verhindert das allerdings eher Optimierung, als
dass es MCU-spezifische Optimierungen aktiviert. Aus ebendiesem Grunde
benutze ich es persönlich dafür gar nicht. Die größere "Freiheit", dass
ich main() dann auch als "void" deklarieren darf, nützt mir praktisch
nichts. Der Rest der üblichen Bibliotheken ist in den Teilen, in denen
die Funktionalität des Standards implementiert wird (also der gleiche
Namensraum wie vom Standard benannt) recht gut standardkonform,
zumindest bei AVR und ARM. (Von der newlib-nano halte ich persönlich
nicht so viel, die meisten ARMs sind groß genug, dass sie die
Vollversion der newlib problemlos nehmen können.)
Bibliotheksfunktionalität, die nicht benutzt wird, kostet ja
normalerweise auch nichts.
Bauform B. schrieb:> Jein, für uC kann man (sollte man? wird man normalerweise?)> -ffreestanding angeben.
Würde ich nicht machen. Im avr-gcc gibt es zum Beispiel Optimierungen,
die NICHT für freestanding gemacht werden.
Und das betrifft dann ziemlich jedes Programm, weil es um main geht (das
bei freestanding keine Sonderrolle hat).
Johann L. schrieb:> Bauform B. schrieb:>> Jein, für uC kann man (sollte man? wird man normalerweise?)>> -ffreestanding angeben.>> Würde ich nicht machen. Im avr-gcc gibt es zum Beispiel Optimierungen,> die NICHT für freestanding gemacht werden.
Ja, tatsächlich
freestanding
1
20424 24 1952 22400 5780 BUILD/syslib.elf
2
6476 0 716 7192 1c18 BUILD/init.elf
3
2884 0 832 3716 e84 BUILD/gps.elf
4
528 0 0 528 210 BUILD/tzdata.elf
hosted
1
20412 24 1952 22388 5774 BUILD/syslib.elf
2
6460 0 716 7176 1c08 BUILD/init.elf
3
2916 0 832 3748 ea4 BUILD/gps.elf
4
528 0 0 528 210 BUILD/tzdata.elf
Aber per Definition sind uC-Programme eindeutig freestanding.
Konsequenterweise sage ich dem Linker auch noch -nostdlib. Irgendwie war
das ganz zu Anfang einfacher und übersichtlicher und jetzt ist es
Tradition.
ist einfach wie eine Vokabel - vlt eher noch eine Redewendung in C, die
man auswendig lernt.
Sie bedarf keiner Verbesserung. Jeder C Programmierer mit etwas
Erfahrung kennt das, wieso künstlich irgendwelche Konstrukte erfinden /
bauen, die etwas triviales hübscher machen.