Forum: Mikrocontroller und Digitale Elektronik while (1) Äquivalenz


von Keine Ahnung (Gast)


Lesenswert?

1
while (1)
äquivalent zu?
1
void FunktionA (void)
2
void FunktionB (void)
3
4
void FunktionA()
5
{
6
  FunktionB();
7
}
8
9
void FunktionB()
10
{
11
  FunktionA();
12
}

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Nein.

von mh (Gast)


Lesenswert?

Das eine läuft für immer, das andere nur bis der Stack voll ist.

von bingo (Gast)


Lesenswert?

mh schrieb:
> , das andere nur bis der Stack voll ist

;)

von Paul H. (powl)


Lesenswert?

Hallo?

Text?

Dankeschön?

Tschüss?

Kennste?

von BumsFallera (Gast)


Lesenswert?

10:
goto 10

von Einer K. (Gast)


Lesenswert?

for(;;);

von mh (Gast)


Lesenswert?

Keine Ahnung schrieb:
> while (1)
> äquivalent zu?
> void FunktionA (void)
> void FunktionB (void)
>
> void FunktionA()
> {
>   FunktionB();
> }
>
> void FunktionB()
> {
>   FunktionA();
> }

C++: vermutlich Ja.
C: vermutlich Nein.

Vorausgesetzt es gibt irgendwo ein main(){functionA();} ...

von A. S. (Gast)


Lesenswert?

Warum der Weg über B und nicht gleich A rekursiv?

von Ben B. (Firma: Funkenflug Industries) (stromkraft)


Lesenswert?

JMP $

von xyz (Gast)


Lesenswert?

Sowas geht nur in LISP gut.

von Oliver S. (oliverso)


Lesenswert?

mh schrieb:
> C++: vermutlich Ja.
> C: vermutlich Nein.

Eins von beiden ist vermutlich falsch.

Oliver

von mh (Gast)


Lesenswert?

Oliver S. schrieb:
> Eins von beiden ist vermutlich falsch.

Wieso? Falls du es nicht wusstest
1
while(1){}
ist in c++ nicht erlaubt. Es geht also nur um die Rekursion ohne 
"forward progress"

von Einer K. (Gast)


Lesenswert?

mh schrieb:
> while(1){}
> ist in c++ nicht erlaubt.

Ja?
Wo kann man das nachlesen?

von tobi (Gast)


Lesenswert?

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
void FunktionA()
2
{
3
  __asm jmp FunktionB
4
}
5
6
void FunktionB()
7
{
8
  __asm jmp FunktionA
9
}

Du kannst ansonsten wie BumsFallera sagt, einfach keine Funktionen 
nutzen, sondern Label und dann das goto Schlüsselwort nutzen:
1
{
2
FunktionA:
3
  goto FunktionB;
4
FunktionB:
5
  goto FunktionA;
6
}

von mh (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> mh schrieb:
>> while(1){}
>> ist in c++ nicht erlaubt.
>
> Ja?
> Wo kann man das nachlesen?

http://eel.is/c++draft/intro.progress
1
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 ]

von Einer K. (Gast)


Lesenswert?

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 ...

von mh (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Du möchtest mir sagen, ...

Nein, möchte ich nicht. Aber der gcc könnte etwas anderes machen, wenn 
er will.

von mh (Gast)


Lesenswert?

clang optimiert den Aufruf von foo in folgendem Beispiel weg.
1
void foo() {
2
  while(true) {}
3
}
4
5
int main() {
6
  foo();
7
  return 0;
8
}
Das Programm terminiert.
Dagegen bleibt die while-Schleife in:
1
int main() {
2
  while(true) {}
3
  return 0;
4
}
erhalten.

von xyz (Gast)


Lesenswert?

1
> void FunktionA()
2
> {
3
>   __asm jmp FunktionB
4
> }
5
6
> void FunktionB()
7
> {
8
>   __asm jmp FunktionA
9
> }


Das waere ja gemogelt. Aber evtl taete es ein:
1
void __attribute__ ((naked)) FunktionA (void)
2
void __attribute__ ((naked)) FunktionB (void)
3
4
void __attribute__ ((naked)) FunktionA()
5
{
6
  FunktionB();
7
}
8
9
void __attribute__ ((naked)) FunktionB()
10
{
11
  FunktionA();
12
}

von Christian S. (roehrenvorheizer)


Lesenswert?

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

von Hermann K. (r2d2)


Lesenswert?

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);

von Rolf M. (rmagnus)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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?

von Rolf M. (rmagnus)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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
void foo() {
4
  for(;;);
5
}
6
7
int main() {
8
  std::cout << "begin\n";
9
  foo();
10
  std::cout << "end\n";
11
  return 0;
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.

von mh (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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)

von Oliver S. (oliverso)


Lesenswert?

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

von sid (Gast)


Lesenswert?

Rekursion ist doch was feines...
endlosschleifen auch.. warum also nicht..
wie wär's hiermit:
1
int ack(int a, int b)
2
{
3
   int c;
4
   if (a==0) c = b+1;
5
   else if (b==0) c = ack(a-1,1);
6
   else c = ack(a-1, ack(a, b-1));
7
   return c;
8
}
und nu nurmal so aus Spass.. was einfaches.. ack(4,3) zB..
ich denke das darf man dann auch als Endlossschleife bezeichen :D

Mahlzeit

'sid

von mh (Gast)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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?

von Rolf M. (rmagnus)


Lesenswert?

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.

von Udo S. (urschmitt)


Lesenswert?

Der Threadstarter kriegt von mir 9 von 10 Troll-Punkte.
So eine blöde aber effektive Frage.
Er musste nicht mal nachfüttern.

von mh (Gast)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

mh schrieb:
> In eine Endlosschleife laufen.

Womit wir wieder beim Problem wären...

von Einer K. (Gast)


Lesenswert?

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.

von Yalu X. (yalu) (Moderator)


Lesenswert?

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:

1
  for(;;) {
2
    volatile char x;
3
    (void)x;
4
  }

In standardkonformen C reicht schon

1
  for(;;);

: Bearbeitet durch Moderator
von Yalu X. (yalu) (Moderator)


Lesenswert?

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).

von Yalu X. (yalu) (Moderator)


Lesenswert?

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 :)

: Bearbeitet durch Moderator
von Einer K. (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von sid (Gast)


Lesenswert?

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

von sid (Gast)


Lesenswert?

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

von mh (Gast)


Lesenswert?

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).

von DPA (Gast)


Lesenswert?

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?

von Udo S. (urschmitt)


Lesenswert?

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.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

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.

von sid (Gast)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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).

von S. R. (svenska)


Lesenswert?

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.

von sid (Gast)


Lesenswert?

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

von mh (Gast)


Lesenswert?

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 ;-)

von Ralf D. (doeblitz)


Lesenswert?

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. :-)

von Christopher J. (christopher_j23)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Toby P. (Gast)


Lesenswert?

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.

von Toby P. (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Einer K. (Gast)


Angehängte Dateien:

Lesenswert?

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

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

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.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

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

von S. R. (svenska)


Lesenswert?

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.

von Larry (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

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;"

Beitrag #6244112 wurde vom Autor gelöscht.
von Rolf M. (rmagnus)


Lesenswert?

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.

von mh (Gast)


Lesenswert?

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.
sagt.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

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.

von Christopher J. (christopher_j23)


Lesenswert?

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".

von W.S. (Gast)


Lesenswert?

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.

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