while-Schleife

#2582742
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.
#2582808
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(;;);
Gast #2582813
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......
Gast #2582822
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.
#2582825
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?
#2582844
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.
#2582848
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.
#2582909
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.
#2582924
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.
#2582951
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.
Gast #2582967
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.
#2582974
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.
#2582979
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.
Gast #2586043
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.
Persönliche Seite #2586883
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...
Gast #2590257
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren