Forum: PC-Programmierung while-Schleife


von Da Mo (Gast)


Lesenswert?

Guten Morgen Forum!

Wie darf man folgende Verwendung der while-Schleife verstehen?
1
int main (void)
2
{
3
 funktion();
4
 while(1); //???
5
}

von Stefan (Gast)


Lesenswert?

Na ja, so wie es dasteht..

--> Es ist einfach nur eine Endlosschleife, in dem dein Programm nichts 
macht  :-)

von Michael R. (dj_motionx)


Lesenswert?

Die Schleifenbedingung ist immer erfüllt. => Endlosschleife

von Da Mo (Gast)


Lesenswert?

Da die Bedingung der while-Schleife immer erfüllt ist (blöde Frage: 
wieso ist "1" immer erfüllt?) und keine Anweisungen in der Schleife 
vorhanden sind, bleibt das Programm in der Schleife stehen und wartet 
--> Endlosschleife. Richtig?
1
int main (void)
2
{
3
 funktion();
4
5
 while(1)
6
 {
7
  
8
 }
9
10
}

von Peter II (Gast)


Lesenswert?

Do Ma schrieb:
> blöde Frage:
> wieso ist "1" immer erfüllt?)

weil alles was != 0 = true ist.

von Stefan (Gast)


Lesenswert?

Do Ma schrieb:
> blöde Frage: wieso ist "1" immer erfüllt?

Alles ungleich 0 wird von der Schleife als "erfüllt" interpretiert :-)

So, wie du deinen Code geschrieben hast, funktioniert es nicht, da deine
1
while(1)
2
 {
3
 
4
 }

wegoptimiert wird...

Probiere doch lieber mal soetwas hier:

1
while(1)
2
 {
3
   ;
4
 }

von Peter II (Gast)


Lesenswert?

Stefan schrieb:
> So, wie du deinen Code geschrieben hast, funktioniert es nicht, da deine
> while(1)
>  {
>
>  }
> wegoptimiert wird...

nein das passiert nicht, der compiler darf nichts wegoptimiert was das 
verhalten ändert.

von Da Mo (Gast)


Lesenswert?

Ein Semikolon obwohl keine Anweisung vorhanden ist!? Ok.

von Stefan (Gast)


Lesenswert?

Peter II schrieb:
> nein das passiert nicht, der compiler darf nichts wegoptimiert was das
> verhalten ändert.

Und was genau ändert sich am Verhalten, wenn eine sinnlose 
while-Schleife wegoptimiert wird???

Schau dir am besten mal das Listing an.

von Stefan (Gast)


Lesenswert?

Do Ma schrieb:
> Ein Semikolon obwohl keine Anweisung vorhanden ist!? Ok.

Eleganter ist es natürlich so:
1
while(1)
2
{
3
   asm volatile ("nop");
4
}

Das wird der Compiler mit Sicherheit nicht wegoptimieren.

von Stefan (Gast)


Lesenswert?

Interessant wäre dazu vielleicht diese Lektüre:

http://de.wikipedia.org/wiki/Compiler#Optimierung_von_Schleifen

In diesem Fall trifft Punkt 8 ziemlich genau zu...

von Peter II (Gast)


Lesenswert?

Stefan schrieb:
> Und was genau ändert sich am Verhalten, wenn eine sinnlose
> while-Schleife wegoptimiert wird???

das der code danach erreicht wird ist schon ein unterschied.

von Εrnst B. (ernst)


Lesenswert?

Stefan schrieb:
> In diesem Fall trifft Punkt 8 ziemlich genau zu...

Nochmal: Der Compiler darf beim Optimieren nichts weglassen, wenn das 
das Verhalten des Programms ändern würde.

Er darf z.B.
while(1); durch einen "HALT"-ASM-Befehl ersetzen, wenn die CPU einen 
solchen besitzt.
=> Beides verhindert, dass Code, der nach der Schleife steht, ausgeführt 
wird.
Er darf auch allen Quelltext, der in der funktion nach der Schleife 
steht, entfernen, "unreachable code".
Aber er darf nicht einfach die Schleife weglassen, und so tun als stände 
da nix.

von Peter II (Gast)


Lesenswert?

Stefan schrieb:
> Eleganter ist es natürlich so:
> while(1)
> {
>    asm volatile ("nop");
> }

assember in einer Hochsprache zu verwenden ist also Elegant? Was ist 
wenn die plattform gar kein nop hat?

von Peter II (Gast)


Lesenswert?

Stefan schrieb:
> In diesem Fall trifft Punkt 8 ziemlich genau zu...

nein macht es nicht, denn eine entlosschleife ist keine normale 
schleife.

von Stefan (Gast)


Lesenswert?

Alle die sich jetzt über die Wegoptimierung beschweren:

NOCHMAL LESEN!!!

Es ging ausdrücklich um dieses Konstrukt:
1
while(1)
2
 {
3
 
4
 }

NICHT um dieses hier:
1
while(1)
2
 {
3
   ;
4
 }


Spätestens jetzt sollte dann die Sonne aufgehen :-)

von Stefan (Gast)


Lesenswert?

Peter II schrieb:
> assember in einer Hochsprache zu verwenden ist also Elegant? Was ist
> wenn die plattform gar kein nop hat?

Nenn mir bitte eines...

von Thomas E. (thomase)


Lesenswert?

Stefan schrieb:
> In diesem Fall trifft Punkt 8 ziemlich genau zu...
Na was denn jetzt?
Entweder es trifft zu oder es trifft nicht zu.
"Ziemlich genau" gibt es in der Digitaltechnik und beim Programmieren 
nicht.

Und eine Auf-der-Stelle-Trampel-Schleife wird niemals wegoptimiert.

mfg.

von Peter II (Gast)


Lesenswert?

Stefan schrieb:
> Nenn mir bitte eines...

zeig mir erstmal einen compieler der

while(1) {}

oder

while(1);


wegoptimiert. (gcc macht es zumindest schon mal nicht)

von Thomas E. (thomase)


Lesenswert?

Peter II schrieb:
> gcc macht es zumindest schon mal nicht
Kein C-Compiler macht das. Weil es sonst kein C-Compiler wäre.

mfg.

von Εrnst B. (ernst)


Lesenswert?

Stefan schrieb:
> Spätestens jetzt sollte dann die Sonne aufgehen

Hoffe ich. Spätestens wenn du feststellst, dass in C diese drei 
Konstrukte komplett identisch sind:
1
while(1);
2
while(1) {}
3
while(1) {;}
und zusätzliche Leerzeichen, Einrückungen, Zeilenumbrüche ändern auch 
nichts daran.

Alle drei macht der Compiler zu:
1
.L2:
2
        jmp     .L2
o.Ä.

Das hier hat übrigens auch denselben Effekt
1
for(;;);

von Stefan (Gast)


Lesenswert?

Thomas Eckmann schrieb:
> Stefan schrieb:
>> In diesem Fall trifft Punkt 8 ziemlich genau zu...
> Na was denn jetzt?
> Entweder es trifft zu oder es trifft nicht zu.
> "Ziemlich genau" gibt es in der Digitaltechnik und beim Programmieren
> nicht.

@Thomas Eckmann:

Gaaaaaanz ruhig. Nur für dich kann ich es gerne umformulieren: Punkt 8 
trifft zu.

> Und eine Auf-der-Stelle-Trampel-Schleife wird niemals wegoptimiert.

Dann lese den Code NOCHMAL (und diesmal aufmerksam) durch. Das ist KEINE 
Auf-der-Stelle-Trampel-Schleife sondern ein 
Schleife-mit-total-leerem-Rumpf.

Thomas Eckmann schrieb:
> Kein C-Compiler macht das. Weil es sonst kein C-Compiler wäre.

Selbst gcc macht das, und das auch noch zurecht :-) Gerne kann ich eine 
kleine Wette vorschlagen: Ich bringe Euch den Beweis, und jeder der hier 
dumm ohne Ahnung rumheult zahlt mir meinen Stundensatz......

von Peter II (Gast)


Lesenswert?

@Stefan

dann zeige uns in beispiel, ich habe es selber getestet und habe es 
nicht hinbekommen das er es wegoptimiert. Und wenn hier alle Personen 
einer anderen Meinung sind dann würde ich schon mal fragen warum?

Für so ein beispiel braucht du bestimmt keine 2minuten - bei 100€/h sind 
das knapp 4€. Dann legen wir mal alle zusammen.

von Εrnst B. (ernst)


Lesenswert?

Stefan schrieb:
> Selbst gcc macht das, und das auch noch zurecht
1
#include <stdio.h>
2
void x() {
3
  while(1);
4
  printf("Hallo Welt");
5
}
macht der gcc zu:
1
        .file   "x.c"
2
        .text
3
        .p2align 4,,15
4
.globl x
5
        .type   x, @function
6
x:
7
.LFB22:
8
        .cfi_startproc
9
        .p2align 4,,10
10
        .p2align 3
11
.L2:
12
        jmp     .L2
13
        .cfi_endproc
14
.LFE22:
15
        .size   x, .-x

Wo ist das printf? Und überweist du mir jetzt meinen Stundensatz?

von Stefan E. (sternst)


Lesenswert?

Sorry Namensvetter, aber du schteibst echt Unsinn. Insbesondere 
existiert der Unterschied, den du da zu konstruieren versuchst, gar 
nicht. Deine beiden while Varianten oben sind absolut identisch.

von M. J. (manfred-64)


Lesenswert?

Εrnst B✶ schrieb:
> Wo ist das printf? Und überweist du mir jetzt meinen Stundensatz?

lol
Thema verfehlt, setzen 6

es geht doch darum das das kein Compiler der Welt weg optimiert!
Εrnst B✶ schrieb:
> .L2:
>         jmp     .L2

von Εrnst B. (ernst)


Lesenswert?

Manfred John schrieb:
> es geht doch darum das das kein Compiler der Welt weg optimiert!

Genau das habe ich doch gezeigt. Der Compiler hat die While-Schleife 
drinnen gelassen, und stattdessen das Printf wegoptimiert.

Stefan behauptet/wettet, dass der Compiler das while weglässt, und 
stattdessen das printf ausführt. Das habe ich widerlegt.

von Thomas E. (thomase)


Lesenswert?

Stefan schrieb:
> Gaaaaaanz ruhig. Nur für dich kann ich es gerne umformulieren: Punkt 8
> trifft zu
Jetzt halt' dich mal ein bischen zurück.

Stefan schrieb:
> Selbst gcc macht das, und das auch noch zurecht :-) Gerne kann ich eine
> kleine Wette vorschlagen: Ich bringe Euch den Beweis, und jeder der hier
> dumm ohne Ahnung rumheult zahlt mir meinen Stundensatz......
Angenommen. Wo soll ich meine Rechnung hinschicken?

void Inititialize(void)
{
...
  while(1);
}
...
 170:  ff cf         rjmp  .-2        ; 0x170 <Initialize+0x64>

Und dann erklärst du mal, wie man ein rein interruptgesteuertes Programm 
aufbaut, einen Watchdog-Reset erzwingt oder wie man einen Controller in 
einem definierten Zustand anhält.
Da sind wir jetzt alle sehr gespannt.

mfg.

von Εrnst B. (ernst)


Lesenswert?

Stefan hat vermutlich auf einer Cray das Programmieren gelernt. Die 
haben ja bekanntlich auch eine Endlosschleife innerhalb von 6 Stunden 
abarbeiten können.

von M. J. (manfred-64)


Lesenswert?

#Ernst

SORRY,hab mich da vergugt, dachte das kam von Stefan.

(Wird zeit das ich ne Mütze voll Schlaf bekomme)

von Karl H. (kbuchegg)


Lesenswert?

Do Ma schrieb:
> Ein Semikolon obwohl keine Anweisung vorhanden ist!? Ok.

Das Semikolon IST die Anweisung.
Auch in C gibt es die leere Anweisung.

technisch gesehen gehört in
1
   while( 1 );
das Semikolon nicht zum while, sondern bildet seine eigene, eben die 
leere Anweisung. Folgt man den üblichen Formatierregeln, die besagen, 
dass die abhängige Anweisung im Fall einer Schleife in die nächste Zeile 
kommt und eingerückt wird, wie zb in
1
   while( i < 10 )
2
     printf( "%d", i++ );
dann würde konsequenterweise diese Endlosschleife so geschrieben ...
1
   while( 1 )
2
     ;
... den die abhängige Anweisung besteht nur aus der leeren Anweisung, 
die durch ein Semikolon abgeschlossen wird.

von Karl H. (kbuchegg)


Lesenswert?

Stefan schrieb:

>> Und eine Auf-der-Stelle-Trampel-Schleife wird niemals wegoptimiert.
>
> Dann lese den Code NOCHMAL (und diesmal aufmerksam) durch. Das ist KEINE
> Auf-der-Stelle-Trampel-Schleife sondern ein
> Schleife-mit-total-leerem-Rumpf.

Und?

Du verwechselst da etwas.
Ein Compiler kann eine Schleife nur dann wegoptimieren, wenn er 
nachweisen kann, dass sie NIE ausgeführt wird. Dazu ist es notwendig, 
dass er nachweisen kann, dass die Abbruchbedingung nie erfüllt werden 
kann bzw. nie TRUE ergibt. Das wird ihm allerdings bei einer 
Endlosschleife schwer fallen.


1
   while( 0 )
2
     ;
kann wegoptimiert werden. Aber
1
   while( 1 )
2
     ;

kann nicht wegoptimiert werden. Mit dem Inhalt des Schleifenrumpfes, 
wieviele und welche Anweisungen da enthalten sind, hat das so (in diesen 
beiden konkreten Fällen) erst mal nichts zu tun. Der kommt erst zum 
Tragen, wenn es eine Wechselwirkung des Schleifenrumpfes mit der 
Abbruchbedingung gibt oder nicht gibt.

von tomb (Gast)


Lesenswert?

Peter II schrieb:
> nein das passiert nicht, der compiler darf nichts wegoptimiert was das
> verhalten ändert.

Spätestens wenn man zusätzlich ASM verwendet, kommt man drauf, dass der 
Gedanke etwas naiv ist. Nicht umsonst gibt es das Schlüsselwort 
volatile.

Hat jetzt aber natürlich nichts mit oben genannten Problem zutun.

von Εrnst B. (ernst)


Lesenswert?

tomb schrieb:
> Peter II schrieb:
>> nein das passiert nicht, der compiler darf nichts wegoptimiert was das
>> verhalten ändert.
>
> Spätestens wenn man zusätzlich ASM verwendet, kommt man drauf, dass der
> Gedanke etwas naiv ist.

Warum? Hat dir dein Compiler schonmal dein inline-ASM verhunzt?

> Nicht umsonst gibt es das Schlüsselwort
> volatile.

Was dazu dient, dem Compiler mitzuteilen, dass sich eine Speicherstelle 
anders verhält als sich der C-Standard das vorstellt.

d.H. Solang dein Rechner sich so verhält, wie der Compiler das erwartet, 
brauchst du volatile nicht, und es ändert auch nichts am 
Programmverhalten.

von tomb (Gast)


Lesenswert?

Εrnst B✶ schrieb:
> Was dazu dient, dem Compiler mitzuteilen, dass sich eine Speicherstelle
> anders verhält als sich der C-Standard das vorstellt.

volatile teilt den Compiler mit, das Speicherinhalte außerhalb in dem 
von ihm einsichtigen Programfluss verwendet werden können und deshalb 
nicht wegoptimiert werden dürfen.

Und ja, das braucht man schon öfters mal. IRQs sind auch ein klassisches 
Beispiel dafür.

von Karl H. (kbuchegg)


Lesenswert?

tomb schrieb:
> Peter II schrieb:
>> nein das passiert nicht, der compiler darf nichts wegoptimiert was das
>> verhalten ändert.
>
> Spätestens wenn man zusätzlich ASM verwendet, kommt man drauf, dass der
> Gedanke etwas naiv ist. Nicht umsonst gibt es das Schlüsselwort
> volatile.

Das kommt immer drauf an, wie man "Verhalten" definiert und welche 
Vorschriften es für den Compiler gibt, die Umgebung einer Codestelle ins 
Kalkül zu ziehen.

Und bei Assembler ist der Ofen sowieso aus. Zu diesem Thema hat der 
C-Standard im Grunde nur eines zu sagen: Ja, gibt es; aber für Details 
und Nebenwirkungen fragen sie ihren Compilerbauer oder die Doku.

von Karl H. (kbuchegg)


Lesenswert?

tomb schrieb:
> Εrnst B✶ schrieb:
>> Was dazu dient, dem Compiler mitzuteilen, dass sich eine Speicherstelle
>> anders verhält als sich der C-Standard das vorstellt.
>
> volatile teilt den Compiler mit, das Speicherinhalte außerhalb in dem
> von ihm einsichtigen Programfluss verwendet werden können und deshalb
> nicht wegoptimiert werden dürfen.
>
> Und ja, das braucht man schon öfters mal. IRQs sind auch ein klassisches
> Beispiel dafür.

Du sprichst von speziellen C Implementierungen, während sich andere 
darauf konzentrieren möchten, was der Sprachstandard dazu zu sagen hat. 
Standard C hat keine Notation für IRQs oder Memory Mapped Devices oder 
atomaren Zugriff oder Interrupts im Generellen oder Shared Memory oder 
....
All das kommt im ISO Dokument nicht vor. Man hat sich auf ein paar 
Schlüsselwörter geeinigt und der gefordertes Verhalten definiert welche 
in den genannten Themenkreisen nützlich und notwendig sind, ohne diese 
Themenkreise selbst in den Standard mit aufnehmen zu müssen.


Nicht die Dinge durcheinander werfen, sonst sind Missverständnisse 
vorprogrammiert.

von Uwe (Gast)


Lesenswert?

Wenn er das while(1);  Wegoptimieren würde dann würde der PC einfach 
immer weiter inkrementiert und der Blödsinn der dahinter steht 
ausgeführt. Da nicht spezifiziert ist was dahintersteht würden eventuell 
komische Sachen passieren. Dannn würde irgendwann der PCam Ende des 
Speichers ankommen Überlaufen und wieder bei Adresse 0 anfangen 
(warscheinlich Reset vektor), das Programm würde erneut ausgeführt usw.
Dies wäre (wenn es so wäre, was es nicht ist!) eindeutig eine 
Unzulässige Optimierung.
Es ist halt schon ein unterschied ob ich einen Text auf dem UART ausgebe 
und danch in einer Endlosschlleife warte oder ob ich den Text ausgebe 
und danach nochmal ausgebe usw.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Εrnst B✶ schrieb:
> tomb schrieb:
>> Peter II schrieb:
>>> nein das passiert nicht, der compiler darf nichts wegoptimiert was das
>>> verhalten ändert.
>>
>> Spätestens wenn man zusätzlich ASM verwendet, kommt man drauf, dass der
>> Gedanke etwas naiv ist.

Nö, das gilt immer noch.

Wenn du mit deinem ASM-Code allerdings das Verhalten änderst ohne es 
dem Compiler mitzuteilen, ist dein Code fehlerhaft, nicht der Compiler.

> Warum? Hat dir dein Compiler schonmal dein inline-ASM verhunzt?
>
>> Nicht umsonst gibt es das Schlüsselwort volatile.
>
> Was dazu dient, dem Compiler mitzuteilen, dass sich eine Speicherstelle
> anders verhält als sich der C-Standard das vorstellt.

Aber nicht bei "asm volatile". Da hat "volatile" es eine andere 
Bedeutung.

Und in folgendem Beispiel auch:
1
#include <stdio.h>
2
3
typedef int fn (const char*);
4
          
5
void call (volatile fn f, const char *str)
6
{
7
    f (str);
8
    puts ("Mitte\n");
9
}
10
11
int main()
12
{
13
    call (puts, "Start\n");
14
    call (puts, "Ende\n");
15
    
16
    return 0;
17
}

Preisfrage

Was ist die Ausgabe des obigen C-Programms?

p.s. Einfach durch den Compiler jagen und schauen was der draus macht 
ist laaangweilig...

von Vlad T. (vlad_tepesch)


Lesenswert?

Johann L. schrieb:
> Was ist die Ausgabe des obigen C-Programms?

Ich bekomme beim kompilieren Warnungen.

Bitte erklär das Verhalten. ich kann es überhaupt nicht nachvollziehen, 
weiß aber auch nicht, was das volatile in dem Zusammenhang überhaupt für 
einen Zweck haben soll.

von borg (Gast)


Lesenswert?

Vlad Tepesch schrieb:

> Ich bekomme beim kompilieren Warnungen.

Alle Warnungen bekommt man zumindest bei gcc weg, indem man vor main() 
noch die Zeile einfügt:
1
volatile fn puts;

Wieder was gelernt heute... Hoffentlich brauche ich das nie.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Auf nen PC losgelassen zeigt das Programm ein nettes Verhalten ;-)

von Rolf M. (rmagnus)


Lesenswert?

Naja, laut ISO C ist das Verhalten undefiniert. Paßt also ;-)

von Mark B. (markbrandis)


Lesenswert?

borg schrieb:

> Alle Warnungen bekommt man zumindest bei gcc weg, indem man vor main()
> noch die Zeile einfügt:
1
volatile fn puts;

Bei mir gibt es dann die folgende Warnung mit gcc Version 3.4.5 (sowohl 
bei Übersetzung mit -Wall als auch ohne):

1
warning: `noreturn' function returns non-void value

von borg (Gast)


Lesenswert?

Mark Brandis schrieb:

> Bei mir gibt es dann die folgende Warnung mit gcc Version 3.4.5 (sowohl
> bei Übersetzung mit -Wall als auch ohne):
>
> warning: `noreturn' function returns non-void value

Das ist auch eine vernünftige Warnung (ich kann jetzt nicht 
nachvollziehen, warum ich die nicht bekommen habe).

Es wäre aber kein Problem, ein ähnliches Beispiel zu schreiben, um ohne 
Warnungen ein undefiniertes Verhalten zu bekommen: Man lügt den Compiler 
an, indem man sagt: "Aus dieser (void-)Funktion wird nicht zurückgekehr, 
optimiere entsprechend." Sobald Aufrufer und Implementierer in 
unterschiedlichen Übersetzungseinheiten liegen, kann der Compiler diese 
Lüge kaum noch aufdecken und anwarnen.

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.