Der (endliche) Stack wird überlaufen.
Wenn eine Funktion aufgerufen wird, muss der Computer beim Verlassen der
Funktion rauskriegen, von wo aus die Funktion aufgerufen wurde, damit er
da weitermachen kann. Dafür wird er bei jedem Funktionsaufruf eine
Rücksprungadresse auf dem Stack ("Stapel") ablegen. Wenn eine Funktion
verlassen wird, wird diese Rücksprungadresse wieder entfernt.
Bei dir wird nie eine Funktion verlassen und daher die Rücksprungadresse
auch nie entfernt. Folglich wächst der Stack stetig weiter, bis eben
kein Speicher mehr da ist.
Du könntest das erreichen wie Ben sagt, indem du keine Funktionsaufrufe
verwendest, sondern direkt zu den Funktionen springst. Soweit ich weiß
müsstest du dann aber Assembler Instruktionen verwenden:
1
voidFunktionA()
2
{
3
__asmjmpFunktionB
4
}
5
6
voidFunktionB()
7
{
8
__asmjmpFunktionA
9
}
Du kannst ansonsten wie BumsFallera sagt, einfach keine Funktionen
nutzen, sondern Label und dann das goto Schlüsselwort nutzen:
3 During the execution of a thread of execution, each of the following is termed an execution step:
2
(3.1) termination of the thread of execution,
3
(3.2) performing an access through a volatile glvalue, or
4
(3.3) completion of a call to a library I/O function, a synchronization operation, or an atomic operation.
und
1
5 [ Note: Because of this and the preceding requirement regarding what threads of execution have to perform eventually, it follows that no thread of execution can execute forever without an execution step occurring. — end note ]
Du möchtest mir sagen, dass mein GCC 9.2 und auch alle gerade
erreichbaren Vorgänger defekt sind, weil sie bei "while(1){}" das zu
erwartende Verhalten (Endlosschleife), ohne jede Warnung, zeigen.
Ok ...
Keine Ahnung schrieb:> while (1)> äquivalent zu?> void FunktionA (void)> void FunktionB (void)>> void FunktionA()> {> FunktionB();> }>> void FunktionB()> {> FunktionA();> }
Ist dieses Beispiel hier der Prototyp der neuzeitlichen Fragekultur, bei
dem noch implizit erwartet wird, daß die Leser mehr schreiben sollen als
der Fragesteller und sich noch die Kür einer kompetenten Antwort geben
sollen?
mfG
Bei vielen modernen Compilern wird das bei aktivierter Optimierung
tatsächlich äquivalent sein. Es gibt da die Tail call optimization
(keine Ahnung wie das auf Deutsch heißt).
Ist der letzte Befehl einer Funktion ein Funktionsaufruf wird aus
Aus:
1
...
2
CALL andere Funktion
3
POP benutzte Register
4
RETURN
einfach
1
...
2
POP benutzte Register
3
JUMP andere Funktion
Das spart einen Sprung am Funktionsende und reduziert den maximalen
Stackverbrauch.
Daher würden im obigen Beispiel die Funktionsaufrufe vermutlich als
Sprünge umgesetzt. Und damit ist es äquivalent zum while(1);
Hermann K. schrieb:> Bei vielen modernen Compilern wird das bei aktivierter Optimierung> tatsächlich äquivalent sein. Es gibt da die Tail call optimization> (keine Ahnung wie das auf Deutsch heißt).
Nicht nur das. Bei mir macht gcc sämtliche Aufrufe komplett weg und
ersetzt das ganze durch ein simples:
[Code]
.L7:
jmp .L7
[/C]
mh schrieb:> http://eel.is/c++draft/intro.progress
Das ist ja mal eine bescheuerte Regel.
Rolf M. schrieb:> Das ist ja mal eine bescheuerte Regel.
Ich habe dann mal ein paar Fragen:
- Warum ist die Regel bescheuert?
- Glaubst du, das wurde in den Standard geschrieben, um Leute zu ärgern?
- Kannst du ein gutes Beispiel geben, wo die Regel wirklich stört?
mh schrieb:> Rolf M. schrieb:>> Das ist ja mal eine bescheuerte Regel.> Ich habe dann mal ein paar Fragen:> - Warum ist die Regel bescheuert?
Weil ich keinen Sinn darin erkennen kann.
> - Glaubst du, das wurde in den Standard geschrieben, um Leute zu ärgern?
Nein, aber ich weiß auch nicht, welchem Zweck diese Regel dienen könnte.
> - Kannst du ein gutes Beispiel geben, wo die Regel wirklich stört?
Beispielsweise wenn man einen Scheduler für multithreading hat. Oft muss
ja die überschüssige Rechenzeit irgendwo hin, also wenn kein Thread
gerade irgendwas tun kann. Dafür gibt's den Idle-Thread, der aus einer
einfachen Endlosschleife besteht.
Oder ein Fehler-Handler für einen µC, wo man in einen kritischen Fehler
läuft, dann vielleicht noch über einen Debug-Port Registerinhalte und
sowas augegeben werden und das System danach in eine Endlosschleife
läuft.
Jetzt muss man quasi in solchen Fällen wegen dieser Regel eine
dummy-Variable anlegen, die volatile ist und in jedem Durchlauf gelesen
und verworfen wird, nur damit die Schleife gültig ist, oder wie soll das
laufen?
Und jetzt könntest du mir im Gegenzug ein Beispiel geben, wo diese Regel
wirklich hilft.
mh schrieb:> http://eel.is/c++draft/intro.progress> 3 During the execution of a thread of execution, each of the following> is termed an execution step:> (3.1) termination of the thread of execution,> (3.2) performing an access through a volatile glvalue, or> (3.3) completion of a call to a library I/O function, a synchronization> operation, or an atomic operation.> und5 [ Note: Because of this and the preceding requirement regarding> what threads of execution have to perform eventually, it follows that no> thread of execution can execute forever without an execution step> occurring. — end note ]
Ok.
Aber daraus abzuleiten, daß while(1){} in C++ nicht erlaubt sein, halte
ich für sehr gewagt. Der Abschnitt vor deinem Zitat lautet (andere
Nummerierung, da anscheinend anderer draft):
1
4.7.2 Forward progress[intro.progress]
2
1
3
The implementation may assume that any thread will eventually do one of the following:
4
—(1.1)terminate,
5
—(1.2)make a call to a library I/O function,
6
—(1.3)perform an access through a volatile glvalue, or
7
—(1.4)perform a synchronization operation or an atomic operation.
8
[Note:This is intended to allow compiler transformations such as removal of empty loops, even whentermination cannot be proven.— end note]
Den letzte Satz lese ich so, daß eine leere Endlosschleife wegoptimiert
werden darf, aber nicht, daß die genrell verboten sei.
Oliver
Rolf M. schrieb:>> - Warum ist die Regel bescheuert?>> Weil ich keinen Sinn darin erkennen kann.>>> - Glaubst du, das wurde in den Standard geschrieben, um Leute zu ärgern?>> Nein, aber ich weiß auch nicht, welchem Zweck diese Regel dienen könnte.
Weil du keinen Sinn in der Regel erkennen kannst, ist die Regel
bescheuert? Was soll man dagegen sagen? Ich versuche es mal direkt:
Ich gehe erstmal davon aus, dass es einen sehr guten Grund gibt für
diese Regel. Das ist im Allgemeinen ein gutes Vorgehen, wenn man keine
Ahnung hat. Ist nicht böse gemeint, aber du hast bewiesen, dass du von
diesem speziellen Thema keine Ahnung hast (du kanntest die Regel
nicht, du hast kein Argument außer "dann muss ich Dinge anders lösen").
Rolf M. schrieb:> Und jetzt könntest du mir im Gegenzug ein Beispiel geben, wo diese Regel> wirklich hilft.
Kann ich nicht, ich habe noch nie eine Endlosschleife gebraucht, aber
ich freue mich immer, wenn der Compiler optimiert. Im Standard selbst
steht z.B.
1
[ Note: This is intended to allow compiler transformations such as removal of empty loops, even when termination cannot be proven. — end note ]
also gibt es vermutlich Leute, denen diese Optimierung wichtig ist. Dann
kommt recht häufig "forward progress guarantee" und "lock-free
execution" vor. Also wird es vermutlich Leute geben, die diese Garantie
brauchen. Das ist gut genug für mich.
Zu deinen Beispielen:
-Dein Idle-Thread ist mir etwas suspekt. Es gibt keine Möglichkeit mit
diesem Thread zu interagieren (pausieren, stoppen)? Ist das ein
regulärer Thread oder genießt er eine Sonderbehandlung? Was passiert
wenn die Rechenleistung gebraucht wird?
-Der Fehlerhandler könnte auch einfach das "Programm" terminieren.
Oliver S. schrieb:> Aber daraus abzuleiten, daß while(1){} in C++ nicht erlaubt sein, halte> ich für sehr gewagt.
Ich gebe zu, die Formulierung "verboten" ist etwas zu stark. Aber viel
Platz für Interpretation lässt der von mir zitierte Teil nicht:
1
5 [ Note: Because of this and the preceding requirement regarding what threads of execution have to perform eventually, it follows that no thread of execution can execute forever without an execution step occurring. — end note ]
Ich habe den "Was darf das Programm" Teil zitiert. Du hast den "Was darf
der Compiler" Teil zitiert.
Naja, so ganz dem Prinzip der geringsten Überraschung
https://de.wikipedia.org/wiki/Principle_of_Least_Surprise
entspricht die Wegoptimierung von endlosen Leerschleifen ja nicht
gerade, aber noch viel weniger das, was Clang/LLVM in einigen Fällen
daraus machen zu müssen meint.
Beispiel:
1
#include<iostream>
2
3
voidfoo(){
4
for(;;);
5
}
6
7
intmain(){
8
std::cout<<"begin\n";
9
foo();
10
std::cout<<"end\n";
11
return0;
12
}
Für -O0 entspricht das Verhalten noch voll den Erwartungen, aber mit
höheren Optimierungsstufen sieht die Ausgabe so aus:
1
begin
2
begin
3
Segmentation fault (core dumped)
(Clang 10.0.0 unter Linux)
Möglicherweise ist das ein Bug, vielleicht aber auch eine logische
Konsequenz dieser komischen Optimierungsregel.
mh schrieb:> http://eel.is/c++draft/intro.progress
Das scheint nicht dem C++20-Draft zu entstammen, sondern wohl weiter in
die Zukunft zu blicken. Vielleicht werde diese Dinge ja noch geändert.
Wobei es diesen Unfug in C ja schon seit C11 gibt, allerdings mit einem
entscheidenden Unterschied: Schleifen, deren Abbruchbedingung ein
konstanter Ausdruck ist (wo der Compiler also leicht entscheiden kann,
ob die Schleife terminiert oder nicht), werden ganz klassisch
gehandhabt. Die von Rolf genannten Beispiele sind in C also nach wie vor
realisierbar, wenn man die Endlosschleife als
1
while(1);
1
for(;;);
o.ä. schreibt.
Nur mit Clang/LLVM geeht das nicht, denn da wird die Regel auch für C
angewandt, was aber wohl tatsächlich ein Bug ist.
Yalu X. schrieb:> Das scheint nicht dem C++20-Draft zu entstammen, sondern wohl weiter in> die Zukunft zu blicken. Vielleicht werde diese Dinge ja noch geändert.
Das müsste der 20er Draft Stand 2020-04-09 sein. Müsste ähnlich auch
schon in C++11 gewesen sein.
Yalu X. schrieb:> Wobei es diesen Unfug in C ja schon seit C11 gibt, allerdings mit einem> entscheidenden Unterschied: Schleifen, deren Abbruchbedingung ein> konstanter Ausdruck ist (wo der Compiler also leicht entscheiden kann,> ob die Schleife terminiert oder nicht), werden ganz klassisch> gehandhabt.
Ja in C gibt es eine explizite Ausnahme für Schleifen mit konstantem
Ausdruck als Abbruchbedingung. Ansonsten sind auch da Endlosschleifen
mit nicht konstanter Bedingung Freiwild.
Yalu X. schrieb:> Das scheint nicht dem C++20-Draft zu entstammen, sondern wohl weiter in> die Zukunft zu blicken.
Ich wills nicht hoffen.
Bisher ist mit AVR gcc 9.2 und -std=gnu++2a -Os eine Endlosschleife noch
eine Endlosschleife.
(werde es im Auge behalten)
Yalu X. schrieb:> Das scheint nicht dem C++20-Draft zu entstammen, sondern wohl weiter in> die Zukunft zu blicken. Vielleicht werde diese Dinge ja noch geändert.
Das steht im letzten C++17 Draft (als Kapitel 4.7), und damit vermutlich
auch im C++17-Standard.
Oliver
sid schrieb:> warum also nicht..sid schrieb:> was einfaches.. ack(4,3) zB..
Weil es undefined behaviour ist (signed integer overflow). Alternativ
kannst du mir die Bitbreite des integer Datentyps angeben, mit dem es
funktioniert.
Yalu X. schrieb:> while(1);> for(;;);> Nur mit Clang/LLVM geeht das nicht
Das ist aber eine sehr unangenehme Überraschung.
Aber den von Dir geschilderten Segmentation fault kann wohl niemand mir
gesunder Logik für gewollt halten, oder?
mh schrieb:> Weil du keinen Sinn in der Regel erkennen kannst, ist die Regel> bescheuert? Was soll man dagegen sagen? Ich versuche es mal direkt:> Ich gehe erstmal davon aus, dass es einen sehr guten Grund gibt für> diese Regel. Das ist im Allgemeinen ein gutes Vorgehen, wenn man keine> Ahnung hat. Ist nicht böse gemeint, aber du hast bewiesen, dass du von> diesem speziellen Thema keine Ahnung hast (du kanntest die Regel> nicht, du hast kein Argument außer "dann muss ich Dinge anders lösen").
Du hast aber offenbar genauso wenig Ahnung, weil du auch nicht weißt,
wozu diese Regel dienen soll. Du freust dich aber trotzdem darüber, weil
du denkst, dass sie ja irgendwie gut sein muss. Ich seh's halt einfach
etwas kritischer, auch wenn "bescheuert" zugegebenermaßen nicht die
beste Wortwahl war.
> Rolf M. schrieb:>> Und jetzt könntest du mir im Gegenzug ein Beispiel geben, wo diese Regel>> wirklich hilft.>> Kann ich nicht, ich habe noch nie eine Endlosschleife gebraucht, aber> ich freue mich immer, wenn der Compiler optimiert.
Ich freue mich, wenn er sinnvoll optimiert.
> Im Standard selbst steht z.B.[ Note: This is intended to allow compiler> transformations such as removal of empty loops, even when termination cannot> be proven.> — end note ]> also gibt es vermutlich Leute, denen diese Optimierung wichtig ist.
Das kann ich mir für Schleifen, die nicht endlos sind, durchaus gut
vorstellen. Aber solche Optimierungen waren auch schon vor dieser Regel
erlaubt - nur eben nicht für Endlosschleifen.
> Dann kommt recht häufig "forward progress guarantee" und "lock-free> execution" vor. Also wird es vermutlich Leute geben, die diese Garantie> brauchen. Das ist gut genug für mich.
Für mich eben nicht.
> Zu deinen Beispielen:> -Dein Idle-Thread ist mir etwas suspekt. Es gibt keine Möglichkeit mit> diesem Thread zu interagieren (pausieren, stoppen)?
Der darf niemals pausiert oder gestoppt werden. Das ist ja gerade der
Sinn des Idle-Threads. Er dient als "Auffangbecken" für gerade nicht
benötigte Rechenzeit. Wenn der gestoppt wird, was soll der Prozessor
dann tun, wenn alle anderen Threads gerade blockiert sind?
Das ist übrigens nicht auf meinem Mist gewachsen, sondern ein ziemlich
grundlegendes Element so ziemlich jedes mir bekannten
Multitasking-Systems. Auch Windows hat den. Kann man im Taskmanager als
"Leerlaufprozess" sehen. Wobei der in dem Fall etwas mehr macht als eine
Endlosschleife, nämlich den Prozessor schlafen legen.
> Ist das ein regulärer Thread oder genießt er eine Sonderbehandlung? Was> passiert wenn die Rechenleistung gebraucht wird?
Was soll dann passieren? Dann gibt's einen Taskwechsel zu dem Thread,
der sie braucht. Der Idle-Thread hat natürlich die niedrigste Priorität,
so dass er nur dann drankommt, wenn wirklich kein anderer gerade was zu
tun hat.
> -Der Fehlerhandler könnte auch einfach das "Programm" terminieren.
Auf einem Rechner mit Betriebssystem ja. Aber was verstehst du auf einem
µC unter "das Programm terminieren"? Und was denkst du, was der nach dem
Terminieren macht?
Stefan ⛄ F. schrieb:> Yalu X. schrieb:>> while(1);>> for(;;);>> Nur mit Clang/LLVM geeht das nicht>> Das ist aber eine sehr unangenehme Überraschung.
Und deshalb finde ich es "bescheuert". :)
> Aber den von Dir geschilderten Segmentation fault kann wohl niemand mir> gesunder Logik für gewollt halten, oder?
Soweit ich das beurteilen kann, wäre es aber wohl konform zu der Regel.
Rolf M. schrieb:> Du hast aber offenbar genauso wenig Ahnung, weil du auch nicht weißt,> wozu diese Regel dienen soll. Du freust dich aber trotzdem darüber, weil> du denkst, dass sie ja irgendwie gut sein muss.
Ich habe nie gesagt, dass ich besonders viel Ahnung habe, oder sogar ein
Experte bin. Ich kannte die Regel aber immerhin. Und warum sollte ich
mich nicht darüber freuen wenn der Standard Wert darauf legt, dass
Optimierungen möglich sind? Was soll ich gegen diese Regel haben, wenn
ich in ~15 Jahren c++ noch keine Endlosschleife benötigt habe?
Rolf M. schrieb:> Für mich eben nicht.
Du benötigst für alles was im Standard steht eine Begründung, die deinen
Ansprüchen genügt? Viel Spass beim warten.
Rolf M. schrieb:> Der darf niemals pausiert oder gestoppt werden. Das ist ja gerade der> Sinn des Idle-Threads.
Mir ist klar, was ein Idle-Thread ist. Ich sehe nur nicht so ganz wie
dieses Konzept in c++ funktionieren soll, ohne den Standard zu verlassen
(zusätzlich zu Endlosschleifen).
Rolf M. schrieb:> Auf einem Rechner mit Betriebssystem ja. Aber was verstehst du auf einem> µC unter "das Programm terminieren"? Und was denkst du, was der nach dem> Terminieren macht?
In eine Endlosschleife laufen. Der Compiler/stdlib, darf sie benutzen.
mh schrieb:> wenn> ich in ~15 Jahren c++ noch keine Endlosschleife benötigt habe?
Hmmm...
Wenn mich nicht alles täuscht, dann kann man schon soweit gehen, und
sagen, dass jedes Programm, jeder Prozess, jeder Thread, eine
Endlosschleife benötigt.
Egal wie fett der Prozessor ist, egal welches OS.
Von Win über Linux, und auch FreeRtos.
OK, das "jeder" ist evtl. ganz leicht übertrieben.
Ein paar Sonderfälle kann man da evtl. abziehen.
Aber das bestätigt nur die Regel.
Ob es immer die Kurzform
> while(1);> for(;;);
sein muss, ist eine andere Frage.
Aber Endlosschleifen, die finden sich wie Sand am Meer.
Oftmals, ohne jede Alternative.
Ich glaube, ich hab's jetzt verstanden, musste aber ziemlich lange nach
der Erklärung suchen.
1. Die Formulierung "may assume, that <x>" bedeutet: Ist <x> nicht
erfüllt, ist das undefined Behavior. Damit ist u.a. auch
1
while(1);
undefined Behavior, und "mh" hat recht gehabt mit seiner Behauptung,
dass solche Schleifen verboten sind. Damit ist der Crash in meinem
obigen Beispiel zwar zunächst überraschend, aber dennoch in Ordnung.
2. Bei dieser Regel geht es nicht etwa darum, leere Endlosschleifen
wegzuoptimieren (was ziemlich unsinnig wäre), sondern um solche
durchaus sinnvollen und auch gewünschten Optimierungen:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1528.htm
Somit hat das Ganze durchaus einen Sinn. Leider wissen offensichtlich
nur wenige davon, obwohl es diese Regel schon seit C++11 gibt (als ich
oben schrieb, das müsse etwas Neues sein, habe ich mich getäuscht).
Ich frage mich gerade, welche neueren C++-Lehrbücher auf diesen durchaus
wichtigen Punkt hinweisen. In den Büchern, die ich bisher gelesen habe,
ist mir so etwas nicht aufgefallen.
Wenn man in C++ tatsächlich eine Endlosschleife ohne einen erkennbaren
Effekt braucht, kann man das bspw. so machen:
Arduino Fanboy D. schrieb:> Wenn mich nicht alles täuscht, dann kann man schon soweit gehen, und> sagen, dass jedes Programm, jeder Prozess, jeder Thread, eine> Endlosschleife benötigt.
Endlosschleifen an sich sind ja erlaubt. Verboten sind nur solche, die
keinen Effekt haben (Nichtterminierung zählt in diesem Zusammenhang
nicht als Effekt).
Udo S. schrieb:> Der Threadstarter kriegt von mir 9 von 10 Troll-Punkte.> So eine blöde aber effektive Frage.> Er musste nicht mal nachfüttern.
Da ich heute etwas wirklich Interessantes dazugelernt habe, gebe ich dem
TE ein +1, was ich sonst praktisch nie tue.
Ach ja, "mh" bekommt natürlich ebenfalls ein +1 für
mh schrieb:> while(1){}> ist in c++ nicht erlaubt.
Das war's dann für heute aber auch mit dem +1-Regen :)
Ja, nee....
Der Kollege sagte:
> wenn> ich in ~15 Jahren c++ noch keine Endlosschleife benötigt habe?
DAS habe ich in Zweifel gezogen.
Yalu X. schrieb:> Verboten sind nur solche, die> keinen Effekt haben
Dass mir DAS nicht schmeckt, ist ein ganz anderes paar Schuhe.
Denn ich habe einige Programme im Feld, welche genau diese leere
Schleife verwenden.
Manche, wo es als halt() eingesetzt wird, aus dem nur ein Reset die
Erlösung bringt, und einige, welche eigentlich nur im Interrupt laufen,
und die Schleife dazu dient, ungenutzte Zeit zu vertrödeln.
Yalu X. schrieb:> for(;;) {> volatile char x;> (void)x;> }
Schmeckt mir auch nicht sonderlich gut.
Yalu X. schrieb:> ich heute etwas wirklich Interessantes dazugelernt habe,
Ich auch.
Mal schauen, wann es mir erstmalig auf die Füße fällt.
mh schrieb:> Rolf M. schrieb:>> Für mich eben nicht.> Du benötigst für alles was im Standard steht eine Begründung, die deinen> Ansprüchen genügt? Viel Spass beim warten.
Nicht für alles, aber ich befinde umgekehrt auch nicht alles automatisch
für gut, nur weil's halt da drin steht.
mh schrieb:> Weil es undefined behaviour ist (signed integer overflow). Alternativ> kannst du mir die Bitbreite des integer Datentyps angeben, mit dem es> funktioniert.
'tschuldigung, ich habe die Ackermannfunktion als bekannt vorausgesetzt
und deswegen den Sarkasmus-tag nicht benutzt.
bitbreite.. weiss nicht,dürfte so um 2^(2^65536) sein oder so;
ich ging also davon aus, dass der overflow das geringste aller Probleme
sein dürfte,
da sie eh erst Wochen nach dem Wärmetod des Universums terminiert ;)
und sind wir ehrlich dann ist die korrekte Antwort darauf auch egal :D
Mahlzeit
'sid
Arduino Fanboy D. schrieb:> Denn ich habe einige Programme im Feld, welche genau diese leere> Schleife verwenden.> Manche, wo es als halt() eingesetzt wird, aus dem nur ein Reset die> Erlösung bringt, und einige, welche eigentlich nur im Interrupt laufen,> und die Schleife dazu dient, ungenutzte Zeit zu vertrödeln.
ja..
"Arduino Fanboy" gibt auch Auskunft darüber wo diese Programme dan
eingesetzt werden nehm ich an ;)
klar braucht man in microControllern schonmal ein "Ende"
Das Problem liegt aber daran dass dein Code generell IMMER in einer
Endlosschleife läuft (void loop()) und du dessen Ausführung blockieren
willst, es aber aus besagter loop funktion kein return gibt soweit ich
weiss.
Ausserhalb von µCs allerdings sind solche Schleifen eher unerwünscht
(vorsichtig formuliert) und man will sie um jeden Preis vermeiden, damit
das Programm auch eine Rückgabe erzeugt mindestens eine Fehlermeldung.
Also Äpfel und Birnen, ihr redet klar aneinander vorbei...
'sid
Arduino Fanboy D. schrieb:> mh schrieb:>> wenn>> ich in ~15 Jahren c++ noch keine Endlosschleife benötigt habe?>> Hmmm...>> Wenn mich nicht alles täuscht, dann kann man schon soweit gehen, und> sagen, dass jedes Programm, jeder Prozess, jeder Thread, eine> Endlosschleife benötigt.
Und "jedes Programm, jeder Prozess, jeder Thread" benötigt vermutlich
einen Kontextwechsel. Jetzt rate mal wieviele ich davon standardkonform
in C++ geschrieben habe?
S. R. schrieb:> mh schrieb:>> In eine Endlosschleife laufen.>> Womit wir wieder beim Problem wären...
Hättest du den zweiten Satz gelsen...
mh schrieb:> In eine Endlosschleife laufen. Der Compiler/stdlib, darf sie benutzen.Rolf M. schrieb:> Nicht für alles, aber ich befinde umgekehrt auch nicht alles automatisch> für gut, nur weil's halt da drin steht.
Aber von mir verlangst du, dass ich die genauen Gründe für diese Regel
kenne. Sonst darf ich mich nicht freuen, dass der Standard Regeln
einführt, die den Compilern bessere Möglichkeiten zum Optimieren gibt.
sid schrieb:> 'tschuldigung, ich habe die Ackermannfunktion als bekannt vorausgesetzt> und deswegen den Sarkasmus-tag nicht benutzt.
Ich kenne die Ackermannfunktion, kann in dem Post trotzdem keinen
Sarkasmus erkennen.
sid schrieb:> da sie eh erst Wochen nach dem Wärmetod des Universums terminiert ;)> und sind wir ehrlich dann ist die korrekte Antwort darauf auch egal :D
Das kommt ganz aufs System an. Ich bin in weniger als 1 Sekunde in den
a=0 b=Overflow gerannt für ack(4,3).
Yalu X. schrieb:> aber mit> höheren Optimierungsstufen sieht die Ausgabe so aus:>> begin> begin> Segmentation fault (core dumped)
Wow, gerade auch mit clang 8.0.0-3~ubuntu16.04.1 versucht, mit Optionen
"clang++-8 -O2 -std=c++14 -Wall -Wextra -pedantic". Selbes Ergebnis, und
vor allem, keine Warnung!!! Mit clang 3.8 lief es noch. Also,
normalerweise verstehe ich es ja, wenn wegen UB etwas anders/nicht
läuft, normalerweise gibt es zumindest nen vernünftigen Grund dafür.
Aber das hier, das geht gar ja wohl nicht! Ohne die geringste Warnung,
trotz maximaler Warnhöhe, ein Programm, wegen einem Teil, wo niemand
bestreiten würde, was es tun sollte, derart zu Zerreissen, also da hört
mein Verständnis für sowas dann doch mal langsam auf. Weiss jemand,
wer dafür verantwortlich ist?
Yalu X. schrieb:> Da ich heute etwas wirklich Interessantes dazugelernt habe, gebe ich dem> TE ein +1, was ich sonst praktisch nie tue.>> Ach ja, "mh" bekommt natürlich ebenfalls ein +1 für
Hmm, das ist ein Beweis dass auch aus Trollversuchen noch was Gutes
entstehen kann. :-)
Aber das war ziemlich sicher ein unbeabsichtigter Effekt des TOs.
DPA schrieb:> Wow, gerade auch mit clang 8.0.0-3~ubuntu16.04.1 versucht, mit Optionen> "clang++-8 -O2 -std=c++14 -Wall -Wextra -pedantic". Selbes Ergebnis
Der Crash entsteht dadurch, dass das kompilierte main() am Ende kein RET
bzw. RETQ hat.
Für mich sieht es so aus, als ob der Compiler bzgl. der Endlosschleife
etwas zwiegespalten ist:
Sein erste Gedankengang:
"foo() enthält ja eine Endlosschleife, also ist in main() alles nach dem
Aufruf von foo() (einschließlich der impliziten return-Anweisung)
unreachable Code, der wegoptimiert werden kann."
Dann sagt er sich:
"Die Schleife in foo() hat ja überhaupt keinen Effekt (im Sinne des
Standards), also muss sie laut Standard terminieren. Wenn sie aber
nichts tut und terminiert, kann sie ebenfalls wegoptimiert werden."
Der erste Schritt beruht also darauf, dass die Schleife endlos ist, der
zweite auf dem Schluss, dass die Schleife gar nicht endlos sein kann,
was eigentlich einen Widerspruch darstellt.
Zurück bleibt schließlich ein verstümmeltes main(), das bei der
Ausführung ins Nirwana läuft. Da bei undefined Behavior der Compiler für
nichts zu garantieren braucht, ist das rein formal auch völlig in
Ordnung. Schuld ist der Programmierer (in diesem Fall also ich ;-)).
> und vor allem, keine Warnung!!!
Ja eine Warnung hätte ich mir hier auch erhofft. Auf Grund des oben
erwähnten Widerspruchs sollte sofort klar sein, dass mit dem Code etwas
nicht stimmt. Ich vermute aber, dass sich die beiden Gedankengänge in
verschiedenen Optimierungsmodulen des Compilers abspielen, die nicht
miteinander kommunizieren, weswegen dieser Widerspruch unentdeckt bleibt
und somit auch keine Warnung ausgegeben werden kann.
mh schrieb:>> da sie eh erst Wochen nach dem Wärmetod des Universums terminiert ;)>> und sind wir ehrlich dann ist die korrekte Antwort darauf auch egal :D> Das kommt ganz aufs System an. Ich bin in weniger als 1 Sekunde in den> a=0 b=Overflow gerannt für ack(4,3).
ne kommt nicht auf das System an,
Du hast nicht ausreichend bits in deinem Computer um es auch nur zu
versuchen..
es benötigt weit mehr bits als Protonen im bekannten Universum
ganz zu schweigen dass der Aufrufstack dir selbst irgendwann in den
Nacken schlägt.
mh schrieb:> Ich kenne die Ackermannfunktion, kann in dem Post trotzdem keinen> Sarkasmus erkennen.
scheinbar kennst Du sie nicht.
Denn dann würdest Du es garnicht erst probieren laufen zu lassen..
selbstredend rennst Du zuerst in nen Overflow; völlig egal wie
Also ist die Frage nach der bitzahl schon völlig Hirnlos in diesem
Zusammenhang.
Und der unumstössliche Beweis, dass Du sie nicht kennst.
(oder ihre grauenhafte Art jmd in die Falle tappen zu lassen)
da die Funktionsparameter kontinuierlich fallend aussehen
und nur der Rückgabewert in Einzelschritten incrementiert,
scheint sie harmlos, tritt einem aber gehörigst in den Allerwertesten
bei nur kleinen Aufrufparametern (4,3) scheint ja überschaubar.
Den Sarkasmus darin erkennt man in der Tat nur wenn man das vorher
weiss.
hättest Du sie erkannt hätte Dir schon
https://de.wikipedia.org/wiki/Ackermannfunktion#Genauere_Betrachtung
geholfen das gehässige an (4,3) zu sehen
Zitat:
----
Wir betrachten nun einen komplexeren Fall, nämlich a ( 4 , 3 ) , den
ersten Funktionswert, der so groß ist, dass er praktisch nicht dezimal
aufgeschrieben werden kann.
...
Wenn wir an dieser Stelle mehrere logische Schritte überspringen,
könnten wir a ( 2 , 5 ) zu 13 auswerten und dann versuchen,
a ( 3 , 13 )
auszuwerten – das ist 65533. Doch schon der nächste Funktionsaufruf
liefert mit a ( 3 , 65533 ) eine Zahl, die weit über die geschätzte
Anzahl
der Atome im Universum hinausgeht. Diese Zahl m wird schließlich in die
Berechnung
a ( 3 , m ) eingesetzt, die irgendwann zu einem Ausdruck
der Form a ( 2 , a ( 2 , a ( 2 , … , a ( 2 , 0 ) … ) ) ) ausgeschrieben
würde, die aber mit unseren Mitteln nicht mehr aufgeschrieben werden
kann.
------------
Wie gesagt, ich habe zu unrecht erwartet dass man sie erkennt;
mein Fehler..
aber dass Du jetzt so tust Du hättest sie erkannt und im selben Atemzug
sagst Du hättest es dennoch probiert (und auch noch ein Ergebniss
erwartet)
dann zeigt das klar, dass Du lügst (oder es dir an Auffassunggabe und
Zurechnungsfähigkeit mangelt)
Sarkasmus nicht erkannt?
sid schrieb:> Rekursion ist doch was feines...> ....> und nu nurmal so aus Spass.. was einfaches.. ack(4,3) zB..> ich denke _das darf man dann auch als Endlossschleife bezeichen_ :D
einfach..(HUST) "darf man als Endlosschleife bezeichnen" (ZAUNPFAHLWINK)
Ja ggf nicht klar genug, deswegen meine obige Entschuldigung;
aber bitte, tu jetzt nicht so als läge es an einer fehlenden Angabe der
bitbreite, denn dir fehlt Kapazität auch nur die Anzahl der bits
auszuschreiben und tu nicht so als sei die Berechnung eine Frage der
Rechenkapazität;
denn auch nur der Gedanke Du seist in der Lage ist völlig absurd.
Lass Deinen Computer mal bis 2^512 hochzählen (in Einzelschritten)
(stop die Zeit!) und dann überleg mal was 2^65536 ungefähr dauern
könnte.
und nun kommen wir zurück auf 2^(2^65536) ... Na?? merkste was?
2^65536 sind etwa 19729 dezimalziffern und das ist nur der exponent.
'sid
Yalu X. schrieb:> Zurück bleibt schließlich ein verstümmeltes main(), das bei der> Ausführung ins Nirwana läuft. Da bei undefined Behavior der Compiler für> nichts zu garantieren braucht, ist das rein formal auch völlig in> Ordnung. Schuld ist der Programmierer (in diesem Fall also ich ;-)).
Das nennt man dann eine "quality of implementation issue". Der Compiler
macht zwar formal nichts falsch, aber seine Handhabung dieser Situation
ist dennoch aus Anwendersicht eher unglücklich.
sid schrieb:> ne kommt nicht auf das System an,> Du hast nicht ausreichend bits in deinem Computer um es auch nur zu> versuchen..
Natürlich kommt es aufs System an, wann man in den Overflow läuft.
sid schrieb:> ganz zu schweigen dass der Aufrufstack dir selbst irgendwann in den> Nacken schlägt.
Der Stack hat noch ordentlich Luft nach oben.
sid schrieb:> scheinbar kennst Du sie nicht.> Denn dann würdest Du es garnicht erst probieren laufen zu lassen..
Ich darf also nicht testen, ob zuerst nen stack overflow oder signed
integer overflow eintritt, und wann genau?
sid schrieb:> Sarkasmus nicht erkannt?>> sid schrieb:>> Rekursion ist doch was feines...>> ....>> und nu nurmal so aus Spass.. was einfaches.. ack(4,3) zB..>> ich denke das darf man dann auch als Endlossschleife bezeichen :D>> einfach..(HUST) "darf man als Endlosschleife bezeichnen" (ZAUNPFAHLWINK)
Auch wenn du das Zitat abänderst ist das kein Sarkasmus, bestenfalls
Ironie.
Für den Fall, dass du irgendwann mit deinen Unterstellungen fertig bist
und zu einer Diskussion bereit bist, fasse ich meinen Standpunkt nochmal
zusammen, den ich mit dem Beitrag
mh schrieb:> sid schrieb:>> warum also nicht..>> sid schrieb:>> was einfaches.. ack(4,3) zB..>> Weil es undefined behaviour ist (signed integer overflow). Alternativ> kannst du mir die Bitbreite des integer Datentyps angeben, mit dem es> funktioniert.
darstellen wollte. Deine Funktion, mit den Werten a=4, b=3 aufgerufen,
produziert einen signed integer overflow und ist nach Standard damit
undefined behaviour. Wenn der Compiler das mitbekommt kann er machen was
er will, z.B. nach 42 Sekunden (lange vor dem Wärmetod des Universums)
den Wert 7353 zurückgeben. Die Bitbreite ist also der entscheidende
Punkt. Und falls du es noch nicht gemerkt hast, deine Antwort
sid schrieb:> bitbreite.. weiss nicht,dürfte so um 2^(2^65536) sein oder so;
ist falsch (mehrere Größenordnungen).
sid schrieb:> einfach..(HUST) "darf man als Endlosschleife> bezeichnen" (ZAUNPFAHLWINK)
Das ist falsch, weil es sich eben nicht wie eine Endlosschleife verhält,
auch nicht für reale Zeitverhältnisse.
mh schrieb:> Auch wenn du das Zitat abänderst ist das kein Sarkasmus, bestenfalls> Ironie.
Ohweh, Mathe nicht, Sprache nicht... naja dann; wie isset mit Religion?
wiki schreibt:
>Sarkasmus kann durch direkte Aussage des Gemeinten oder mittels Ironie
ausgedrückt werden.
Aber lassen wir das, nicht dass Du da in die nächste Selbstgeisselung
rennst.
mh schrieb:> Ich darf also nicht testen, ob zuerst nen stack overflow oder signed> integer overflow eintritt, und wann genau?
ne, brauchste ja nicht.. weiss man ja wenn man die Funktion kennt..
hab ich dir ja sogar zitiert..
sobald die Funktion sich selbst mit (3,65533) aufruft
rennst Du zwangsläufig in einen integer overflow.. EGAL BEI WELCHER
BITBREITE!
und der stack dürfte da noch an zehn Fingern abzuzählen sein.
'würde' das durchlaufen (was es nicht kann...) würde Dir im
darauffolgenden Schritt der stack überlaufen.. genauso zwangsläufig wie
der integer overflow auftritt,
weil das Ergebniss dessen jene besagten 19729 Ziffern sind
(2^65536) und genausooft
würde die Funktion sich selbst verschachtelt aufrufen wollen ('tschüss
stack!');
um dann das (ab sofort nurnoch fiktive) Ergebniss (in der Nähe von
2^2^65536) auszuspucken
besagte Wochen nach dem Wärmetod des Universums, wenn der Stack dann
wieder abzählbar ist.
Wie gesagt, wenn man die Funktion kennt, weiss man das;
man weiss auch dass der integer overflow IMMER exakt einen (fiktiven)
Schritt auf selber stackebene vor dem unausweichlichen Stack Overflow
kommt.
Wie gesagt, Du bestätigst nur nochmals, dass Du die Funktion eben
nicht kennst,
mindestens aber Dir ihrer Gemeinheit nicht im Klaren bist;
maximal glaub ich noch, dass Du mal von ihr gehört hast.
Das ist ansich nichts schlimmes.. (muss man nicht wissen mMn)
Aber ernsthaft, langsam wird es albern mit deinem sich rausreden wollen,
Denn dann allerdings muss ich dir wirklich Ignoranz oder Dummeheit
unterstellen,
anders kann ich mir das nichtmehr erklären wieso man es überhaupt
versucht unter der Prämisse die Funktion "zu kennen".
Ich fürchte fast Du hast nichteinmal eine Ahnung wie gross die Zahlen
sind,
von denen Du da glaubst sie "berechnen" zu können,
was Dich dann allerdings in wirklich schlechtes Licht tauchen würde.
Sone ungefähre Ahnung von Grössenordnung sollte man schon haben
10^80 geschätzte Atome im Universum verglichen mit 2^65536 als EXPONENT
macht einem recht einleuchtend klar (hoffentlich) dass jeder Versuch
zwangläufig vollends NUTZLOS ist.
S. R. schrieb:> Das ist falsch, weil es sich eben nicht wie eine Endlosschleife verhält,> auch nicht für reale Zeitverhältnisse.
da es keine realen Zeitverhältnisse gibt nach dem Wärmetod des
Universums ist der Einwand eher zu vernachlässigen.
Die Funktion KANN sich real nicht "korrekt" verhalten mit den
Aufrufparametern (4,3),
eben WEIL sie die Ackermannfunktion ist und egal welcher Computer sich
eben mit begrenzten Ressourcen zufriedengeben muss.
Mit kleineren Aufrufparametern kann sie sich nicht wie eine
"Endlossschleife" verhalten, weil man eben nur ein Ergebniss
zurückbekommt,
und zwar in sehr realen und überschaubaren "Zeitverhältnissen"
Aber jaja.. ich hab verstanden,
ich bin der Einzige der das lustig fand zu dieser -da müsst ihr aber
zustimmen- ziemlich bekloppten Fragestellung.
'sid
sid schrieb:> Sarkasmus nicht erkannt?sid schrieb:> Aber jaja.. ich hab verstanden,> ich bin der Einzige der das lustig fand
Was soll man dazu sagen?
sid schrieb:> Sarkasmus kann durch direkte Aussage des Gemeinten oder mittels Ironie> ausgedrückt werden.
Falls du es noch nicht weißt, nicht immer ist das "direkte Aussagen des
Gemeinten" Sarkasmus. Es gibt noch andere Bedingungen ;-)
sid schrieb:> Aber jaja.. ich hab verstanden,> ich bin der Einzige der das lustig fand zu dieser -da müsst ihr aber> zustimmen- ziemlich bekloppten Fragestellung.
Nein, ich musste da auch innerlich grinsen. Die Erinnerung an die
Ackermann-Funktion war zwar nur dürftig, aber an die Bösartigkeit bzgl.
Wertebereich und Rekursionstiefe konnte ich mich doch noch erinnern.
Aber wenigstens hat die nachfolgende Diskussion mich dazu gebracht, das
mal tiefer nachzulesen als ich mir das damals (vor einigen Jahrzehnten,
bin halt ein alter Sack ;-) ) im Informatik-Studium angetan habe. Jetzt
kenne ich auch Tetration und Hyperoperatoren. Danke. :-)
Yalu X. schrieb:> Für mich sieht es so aus, als ob der Compiler bzgl. der Endlosschleife> etwas zwiegespalten ist
Das sehe ich auch so. Müsste man mal einen Blick in die LLVM-IR werfen
und das mit dem Assembler-Listing vergleichen. Das sollte etwas mehr
Aufschluss geben.
Rolf M. schrieb:>> - Warum ist die Regel bescheuert?>> Weil ich keinen Sinn darin erkennen kann.
Ah ja. Das ist der Standpunkt "was ICH nicht weiß, das gibt es auch
nicht!" (oder "..darf es nicht geben!")
Ich sehe das wieder mal etwas anders:
Ein while(1) ist eigentlich eine Vergewaltigung einer bedingten
Schleife, genauso wie es ein for(;;) ist. Bedingte Schleifen sind dafür
da, eben BEDINGT zu sein und nicht zur unbedingten Schleife verhunzt zu
werden.
Also ist so etwas einfach nur ein schlechter Programmierstil und ich
habe kein Problem damit, wenn eine Regel so etwas stigmatisiert.
Und wenn man eine tatsächliche unbedingte Schleife haben will, dann
setzt man ein Label und benutzt goto. Das wird ja wohl hoffentlich
nicht mal vom GCC hinweg optimiert. Und Label + goto ergeben die
klassische unbedingte Schleife.
W.S.
W.S. schrieb:> Ah ja. Das ist der Standpunkt "was ICH nicht weiß, das gibt es auch> nicht!" (oder "..darf es nicht geben!")
Nein: Der Standpunkt ist: "was ich nicht für sinnvoll erachte, das muss
ich auch nicht gut finden."
> Ich sehe das wieder mal etwas anders:>> Ein while(1) ist eigentlich eine Vergewaltigung einer bedingten> Schleife, genauso wie es ein for(;;) ist.
Bei while(1) gebe ich dir recht, da man als "Bedingung" etwas einträgt,
das immer wahr ist und somit das Konzept der bedingten Wiederholung
eigentlich ad absurdum geführt wird. Das finde ich jetzt zwar nicht so
kritisch (wenn nicht irgendwelche merkwürdigen Regeln plötzlich dafür
sorgen, dass das nicht mehr so funktioniert, wie man eigentlich erwarten
würde), aber doch unschön.
Bei for aber wurde explizit die Möglichkeit vorgesehen, eine Bedingung
gar nicht angeben zu müssen und damit eine Schleife ohne Bedingung zu
erzeugen. Genau das macht dein for(;;) ja auch. Da wird also nichts
"vergewaltigt", sondern ein Sprachfeature genau für das genutzt, wofür
es gedacht ist.
> Und wenn man eine tatsächliche unbedingte Schleife haben will, dann> setzt man ein Label und benutzt goto. Das wird ja wohl hoffentlich> nicht mal vom GCC hinweg optimiert. Und Label + goto ergeben die> klassische unbedingte Schleife.
Das ist deine Alternative? Label+goto? Naja, begeistert mich nicht sehr.
Im Übrigen fällt auch das unter die hier diskutierte Regel. Die ist
völlig unabhängig davon, auf welchem Weg man die Endlosschleife baut.
W.S. schrieb:> Und Label + goto ergeben die> klassische unbedingte Schleife.
Womit man dann erst am Ende weiß das es eine Endlosschleife ist und auch
das nur vielleicht. Weil wer goto nimmt springt dann auch per goto zum
erroerhandler. Proggst du in Assembler? Da macht das evtl. Sinn.
Der Compiler macht aus while(1) das gleiche wie aus for... und goto.
Der goto man verliert aber die Programmstruktur und darf sich zum Ende
durchwühlen wenn er daraus ne Funktion machen will.
Rolf M. schrieb:> Bei while(1) gebe ich dir recht, da man als "Bedingung" etwas einträgt,> das immer wahr ist und somit das Konzept der bedingten Wiederholung> eigentlich ad absurdum geführt wird.
Warum? Die Bedingung ist halt immer wahr. Wenn 21. Juni dann
Sommersonnenwende ist auch immer wahr. Nur halt nicht jeden Tag.
Man macht das wg. konsistenter Programmstrukturen und ein goto ist da so
fehl am Platze wie while(4 != Pi()) was ja ne "echte" Bedingung mit dem
gleichen Ergebnis wäre.
Toby P. schrieb:> Rolf M. schrieb:>> Bei while(1) gebe ich dir recht, da man als "Bedingung" etwas einträgt,>> das immer wahr ist und somit das Konzept der bedingten Wiederholung>> eigentlich ad absurdum geführt wird.>> Warum?
Wenn ich eine Schleife ohne Bedingung will, möchte ich das möglichst
auch so hinschreiben können und nicht stattdessen als bedingte Schleife
mit einer Bedingung, die sich nie ändert. Einfach weil es eine präzisere
und direktere Beschreibung meiner Absicht ist.
Wie gesagt: Ich finde ein while(1) nicht furchtbar, aber eben weniger
schön als eine Möglichkeit, eine unbedingte Schleife auch ohne Bedingung
zu formulieren. Deshalb bevorzuge ich for(;;).
> Man macht das wg. konsistenter Programmstrukturen und ein goto ist da so> fehl am Platze wie while(4 != Pi()) was ja ne "echte" Bedingung mit dem> gleichen Ergebnis wäre.
Dass ich goto da auch nicht für eine gute Idee halte, hab ich ja schon
geschrieben.
Rolf M. schrieb:> Einfach weil es eine präzisere> und direktere Beschreibung meiner Absicht ist
Naja..
Man kann "Absicht" auf verschiedene Art ausdrücken.
Toby P. schrieb:> Der goto man verliert aber die Programmstruktur und darf sich zum Ende> durchwühlen wenn er daraus ne Funktion machen will.
Bin mittlerweile voll auf Goto!
Klarer:
Listig eingesetzte Goto können die Absicht auch verdeutlichen!
Und gleichzeitig helfen die Komplexität zu verbergen.
Im Anhang mal ein Beispiel, wie das(manchmal) in meiner kleinen
(hauptsächlich AVR) Arduino Welt aussieht.
OK, das ist kein SpeicherSparWunder, aber es drückt die "Absicht" recht
klar aus, auch wenn das goto schön versteckt ist, und einige
Endlosschleifen da rum dümpeln
---
Goto hat seinen schlechten Ruf aus vergangen Zeiten, und mit anderen
Sprachen, als C oder C++, erworben.
Sicherlich kann man mit Goto auch derbe Mist bauen!
Aber das gilt wohl auch für alle anderen Sprachmittel.
PS:
Die Library habe ich nicht dazu gepackt.
1. interessiert vermutlich sowieso keinen hier
2. ist (noch) nicht gefegt und poliert
W.S. schrieb:> Ein while(1) ist eigentlich eine Vergewaltigung einer bedingten> Schleife, genauso wie es ein for(;;) ist. Bedingte Schleifen sind dafür> da, eben BEDINGT zu sein und nicht zur unbedingten Schleife verhunzt zu> werden.>> Also ist so etwas einfach nur ein schlechter Programmierstil und ich> habe kein Problem damit, wenn eine Regel so etwas stigmatisiert.>> Und wenn man eine tatsächliche unbedingte Schleife haben will, dann> setzt man ein Label und benutzt goto. Das wird ja wohl hoffentlich> nicht mal vom GCC hinweg optimiert. Und Label + goto ergeben die> klassische unbedingte Schleife.
Immerwieder geil, dass du jedem hier im Forum Beweisen musst, dass du
nicht programmieren kannst.
goto statt while(1), das wird morgen für Gelächter in der
Teambesprechung sorgen zur Auflockerung.
Toby P. schrieb:> Man macht das wg. konsistenter Programmstrukturen und ein goto ist da so> fehl am Platze wie while(4 != Pi()) was ja ne "echte" Bedingung mit dem> gleichen Ergebnis wäre.
Ähh, der Wert von Pi ist teilweise regional unterschiedlich. Je nachdem,
ob der Wert irgendwann auf 3,2 oder 4 festgelegt wird, wäre die o.a.
Bedingung also wahr oder falsch. Man beachte, dass das
Gesetzgebungsverfahren nur unterbrochen, aber niemals beendet wurde:
https://de.wikipedia.org/wiki/Indiana_Pi_Bill
sid schrieb:>> Das ist falsch, weil es sich eben nicht wie eine>> Endlosschleife verhält, auch nicht für reale Zeitverhältnisse.>> da es keine realen Zeitverhältnisse gibt nach dem Wärmetod des> Universums ist der Einwand eher zu vernachlässigen.
Du hast eine schlecht implementierte Ackermannfunktion als Ersatz für
eine Endlosschleife vorgeschlagen. Die verhält sich aber auf realen
Zeitspannen (z.B. innerhalb eines Monats) nicht wie eine Endlosschleife.
Das Ende des Universums ist da irrelevant, weil der Code schon lange
vorher scheitert. Tjoot.
Meine Endlosschleife auf dem C64 (Commodore Basic V2):
1
10 for i=0 to 9e9
2
...
3
90 next
Der begrenzten Genauigkeit wegen, kann der Endwert nie erreicht
werden.
Vorteil: Die literale Sprungadresse liegt wegen der for-Schleife auf
dem for-next Stack und muss nicht aufwendig gesucht werden.
Toby P. schrieb:> Der Compiler macht aus while(1) das gleiche wie aus for... und goto.
Hast du hier nichts gelesen? Die ganze Diskussion ging darum, daß der
GCC sowas wie while(1) einfach wegoptimiert. Er fährt also dem
Programmierer einfach so über's Maul (!!!) - weil eben mal wieder irgend
wer von den Compilerbauern den Sinn von etwas nicht hat einsehen wollen
und gemäß der Direktive "was ich nicht einsehe, das darf nicht sein"
sowas offenbar zum Wegoptimieren freigegeben hat.
OK, ich selber benutze den GCC aus derartigen Gründen nicht, aber es
erstaunt mich immer wieder, mit was für eigentümlichen Hakeleien die
GCC-Benutzer sich herumschlagen müssen.
Was also tun, wenn sowas wie while(1) nicht geht? Mir fällt (siehe oben)
da nur das dedizierte GOTO marke ein, in der Hoffnung, daß die
Compilerbauer nicht derart frech sind, dieses ebenfalls wegzuoptimieren.
Muß man beim GCC mit der Brechstange programmieren?
Wie schonmal gesagt: von einem Compiler erwarte ich, daß er das, was ich
hingeschrieben habe, richtig und optimal in Maschinencode übersetzt -
aber er hat nicht auf eigene Faust irgendwas zu unterschlagen - bloß
weil irgendwer das nicht einsehen wollte.
W.S.
W.S. schrieb:> OK, ich selber benutze den GCC aus derartigen Gründen nicht, aber es> erstaunt mich immer wieder, mit was für eigentümlichen Hakeleien die> GCC-Benutzer sich herumschlagen müssen.
Der gcc macht diese Optimierung gerade NICHT.
Mal davon abgesehen, dass der Nutzer einen Fehler gemacht hat, wenn er
den gcc zum Compilieren von C++ benutzt, dafür ist der g++ gedacht.
W.S. schrieb:> Die ganze Diskussion ging darum, daß der> GCC sowas wie while(1) einfach wegoptimiert.
Nö, der GCC tut das nicht.
Clang tut es und der Standard erlaubt es auch.
Und damit betrifft das auch dich, egal welchen Compiler du benutzt.
W.S. schrieb:> Mir fällt (siehe oben) da nur das dedizierte> GOTO marke ein, in der Hoffnung, daß die> Compilerbauer nicht derart frech sind,> dieses ebenfalls wegzuoptimieren.
Der Standard verbietet endlose, effektfreie Codesequenzen. Das betrifft
damit auch dein "lbl: goto lbl;"
mh schrieb:> Mal davon abgesehen, dass der Nutzer einen Fehler gemacht hat, wenn er> den gcc zum Compilieren von C++ benutzt, dafür ist der g++ gedacht.
GCC ist die GNU Compiler Collection. Zu der gehört das C++-Frontend g++
und das allgemeine Frontend für alle unterstützten Sprachen gcc.
Rolf M. schrieb:> GCC ist die GNU Compiler Collection.
Dann ist es aber nicht "der/den GCC" ;-)
Rolf M. schrieb:> Zu der gehört das C++-Frontend g++ und das allgemeine Frontend für alle
unterstützten Sprachen gcc.
Das ist mir bekannt. Mir ist aber auch bekannt, dass das unter anderem
beim Linken einige Probleme machen kann (einfachster Fall stdlib von
Hand dazulinken). Es gibt nen Grund warum es den g++ gibt und der gcc
selbst
1
When you compile C++ programs, you should invoke GCC as g++ instead.
W.S. schrieb:> Er fährt also dem> Programmierer einfach so über's Maul (!!!) - weil eben mal wieder irgend> wer von den Compilerbauern den Sinn von etwas nicht hat einsehen wollen> und gemäß der Direktive "was ich nicht einsehe, das darf nicht sein"> sowas offenbar zum Wegoptimieren freigegeben hat.
Es sind immer die selben Ammenmärchen die von dir kommen.
Von allen Seiten wurdest du jetzt schon zig mal zu diesem Thema
aufgeklärt.
Deine Borniertheit und Starrsinnigkeit ist hier im Forum echt
unübertroffen.
W.S. schrieb:> OK, ich selber benutze den GCC aus derartigen Gründen nicht, aber es> erstaunt mich immer wieder, mit was für eigentümlichen Hakeleien die> GCC-Benutzer sich herumschlagen müssen.
Ja, du benutzt den Keil, weil der ja sooo viel besser ist als der GCC
aber soll ich dir mal ein Geheimnis verraten (was eigentlich gar nicht
so geheim ist)?
Der "Keil" nutzt in seinen aktuellen Versionen ("ARM Compiler Version
6") Clang/LLVM als Unterbau, also genau den Compiler mit den
"eigentümlichen Hakeleien".
Christopher J. schrieb:> Der "Keil" nutzt in seinen aktuellen Versionen
Der geht mich nix an. Meine Lizenz ist schon ein paar Jährchen alt - und
sie reicht aus für alles, was bei mir anfällt.
W.S.