Fehler im Buch "C von A bis Z"?
-
Hi!
Ich lese zur Zeit das Buch "C von A bis Z" um meine C-Kenntnisse mal wieder aufzufrischen. Beim Durchlesen fiel mir allerdings ein Fehler auf, zumindest glaube ich das.
Und zwar heißt es im im Kapitel 12.10.1 (Funktionen - Typ-Qualifizierer - volatile, hier der Text im Zusammenhang: http://www.pronix.de/pronix-703.html), dass in der Schleife[cpp]do { printf("Gerät X wird überprüft ...\n"); } while(reg & (STATUS_A|STATUS_B) == 0); printf("Gerät X Status ... [OK]\n");[/cpp]
"volatile" nötig wäre, damit der Compiler nicht die gesamte Schleife wegoptimiert.
Ist es nicht vielmehr so, dass der Optimierer das Ganze so optimieren würde:[cpp]bool b = reg & (STATUS_A | STATUS_B); do { printf("Gerät X wird überprüft ...\n"); } while(b == 0); printf("Gerät X Status ... [OK]\n");[/cpp]
Natürlich ist die Behauptung, dass hier "volatile" erforderlich ist, richtig, imho allerdings nicht, dass die gesamte Schleife wegoptimiert werden würde.
Vielmehr wird der boolsche Ausdruck soweit optimiert, dass er nur ein einziges Mal ausgewertet wird und nicht immer wieder neu berechnet wird.Sehe ich da was falsch, oder ist das ein kleiner Fehler im Buch?
Viele Grüße,
m3ph1570PS: Ansonsten ist das Buch zum Wiederauffrischen perfekt geeignet.
-
wenn reg volatile sein soll, dann wird es wahrscheinlich von aussen veraendert und die schleife checkt, ob/wann/wie es veraendert wird und reagiert (miserable art, so ein tight loop).
der compiler wuerde beim volatile nichts optimieren.
ohne volatile kannst du nicht sicher sein. der compiler koennte ja erwarten, dass reg (wenns global ist) durch printf geaendert werden koennte...nach asm compilen und vergleichen
edit: die schleife WUERDE wegfallen, jedoch bliebe das printf noch uebrig. nur der vergleich wuerde (insofern moeglich) schon beim compilen ausgewertet werden.
-
so, ich hab jetzt einfach mal ein kurzes Beispielprogramm geschrieben:
#include <stdio.h> int main() { int reg = 0; int STATUS_A = 1; int STATUS_B = 0; do { printf("Gerät X wird überprüft ...\n"); } while((reg & (STATUS_A|STATUS_B)) == 0); printf("Gerät X Status ... [OK]\n"); return 0; }
Dann hab ich das ganze disassembliert (ganz simpel mit "$objdump -d <executable>"
). Hier ein Ausschnitt:
8048398: c7 45 f4 00 00 00 00 movl $0x0,0xfffffff4(%ebp) 804839f: c7 45 f8 01 00 00 00 movl $0x1,0xfffffff8(%ebp) 80483a6: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp) [b]80483ad:[/b] [b]83 ec 0c[/b] [b]sub[/b] [b]$0xc,%esp[/b] 80483b0: 68 94 84 04 08 push $0x8048494 80483b5: e8 ee fe ff ff call 80482a8 <puts@plt> 80483ba: 83 c4 10 add $0x10,%esp 80483bd: 8b 45 fc mov 0xfffffffc(%ebp),%eax 80483c0: 0b 45 f8 or 0xfffffff8(%ebp),%eax 80483c3: 23 45 f4 and 0xfffffff4(%ebp),%eax 80483c6: 85 c0 test %eax,%eax [b]80483c8:[/b] [b]74 e3[/b] [b]je[/b] [b]80483ad <main+0x31>[/b] 80483ca: 83 ec 0c sub $0xc,%esp 80483cd: 68 b2 84 04 08 push $0x80484b2 80483d2: e8 d1 fe ff ff call 80482a8 <puts@plt> 80483d7: 83 c4 10 add $0x10,%esp 80483da: b8 00 00 00 00 mov $0x0,%eax 80483df: c9 leave
Der Bereich zwischen den fettgedruckten Zeilen stellt die Schleife dar.
Diese wird also nicht, wie in dem Buch behauptet, wegoptimiert.Aber wenn ich das richtig sehe, dann hat der gcc da gar nix optimiert.
Mit den Zeilen80483bd: 8b 45 fc mov 0xfffffffc(%ebp),%eax 80483c0: 0b 45 f8 or 0xfffffff8(%ebp),%eax 80483c3: 23 45 f4 and 0xfffffff4(%ebp),%eax
werden doch jedesmal in der Schleife die bool-Variablen aus dem Speicher geladen und neu verknüpft, oder?
Viele Grüße,
m3ph1570
-
C von A bis Z schrieb:
Manche Compiler erkennen jetzt an der while-Schleife, dass hier immer auf die gleiche Adresse überprüft wird, und optimieren die do while-Schleife einfach weg.
Offenbar gehört der gcc zu den Compilern, die das nicht optimiert haben (oder du hast ihm die Optimierung abgeschaltet).
-
Hm, abgeschaltet habe ich das nicht. Aber eigentlich erzeugt der gcc doch recht vernünftigen Code, wenn man sich son die Benchmarks ansieht...
-
man probiere "-O2" oder "-03" oder schaue in die GCC doku nach den schaltern