Forum: Compiler & IDEs Optimizer fehlerhaft?


von Markus (Gast)


Lesenswert?

Hi,
Mir ist grad beim Programmieren aufgefallen das sich ein Programm
anders verhält wenn man den Optimizer einschaltet. Ist etwas schwierig
zu erklären wo und wie das genau passiert. Aber vielleicht gibts ja
irgendwelche allgemeinen Regeln anhand derer man das nachvollziehen
kann. Vielleicht könnt ihr mir da weiterhelfen.

Gruß
Markus

von Rolf Magnus (Gast)


Lesenswert?

Allgemeine Regeln für Probleme mit dem Optimizer? Gibt's bestimmt... zu
Tausenden.

von Markus (Gast)


Lesenswert?

Ok, fang mal an aufzuzählen ;)
Spaß beiseite, hab ich vermutet. Aber wie kann ich an das Problem
rangehen ohne graue Haare zu kriegen?

von Karl H. (kbuchegg)


Lesenswert?

Optimizer sind auch nur Programme und haben als solche
Fehler.
Meistens ist es aber so, dass du irgendwelche C Regeln
verletzt hast, die sich bei einem normalen Debug-Build
nicht auswirken. Erst wenn der Optimizer loslegen darf,
treten die Fehler dann zu Tage, da der Optimizer laut
C-Sprachstandard irgendwelche Annahmen treffen darf,
die du aber ignoriert, bzw. verletzt hast.

Klassische Dinge am PC sind zb:
* Bei einem Debug Build werden zwischen den Variablen
  oft und gerne ein paar Füll-Bytes eingeschoben. Vor
  allem bei Arrays ist das häufig der Fall. Wenn du einen
  Array nur schreibend wenig überläufst, dann merkst du
  das nicht, da die illegalen Zugriffe in diesen Füll-Bytes
  stattfinden. Erst wenn bei einem optimierten Build diese
  Füll-Bytes nicht mehr da sind, verändern sich dann plötzlich
  Variablen wie von Geisterhand
* Oft übersieht man auch, dass laut Sprachstandard lokale
  Variablen nicht initialisiert werden. Bei Debug Builds
  ist es jedoch oft so, dass die Compiler die Variablen mit
  irgendeinem konstanten Wert initialisieren.

Wie schon gesagt: Klar haben auch Optimizer Fehler. Genauso wie
alle Compiler insgesammt den einen oder anderen Fehler haben.
Aber in 99% aller Fälle ist es das vom Programmierer geschriebene
Programm, und nicht der Compiler, das den eigentlichen Fehler
enthält.

Finden kannst du sowas meist nur mit einer Stufenmethode:
Kommentiere aus deinem Programm alles aus und fange bei 0 an.
Danach werden sukzessive Teilbereiche wieder aktiviert bis
sich das erste mal wieder ein Fehler zeigt. Der Fehler muss nicht
zwangsläufig im zuletzt aktivierten Bereich sein, oft ist er
es aber. Zumindest liefert aber der zuletzt aktivierte Bereich
Hinweise, wo den das eigentliche Problem sitzen könnte.

von Markus (Gast)


Lesenswert?

Das es nicht am Optimizer selber liegt war mir schon vorher klar, aber
ich dachte mir das lesen mehr ;)

Ich habe einen Pointer deklariert, aber nicht die Größe definiert

hatte das im Programm stehen:

char* s;
itoa(*transmitData, s, 16);

trotzdem finde ich es strange das der fehler ohne optimizer weder beim
compilieren noch bei der programmausführung auftritt. ok, letzteres
kann zufall sein, aber der compiler sollte doch in beiden fällen
meckern. Ohne Optimizer ist der Compiler ohne Error oder Warning
durchmarschiert und mit Optimizer kann dann die Meldung:

warning: 's' is used uninitialized in this function

von ABu (Gast)


Lesenswert?

Auf welcher Platform willst du Kompilierten?
Bei einem MCU lohnt sich meiner Erfahrung nach immer ein Blick auf den
ASM-Code.
Ich hatte auch schon einige Fehler bei denen ich den Comiler verflucht
hab und nach dem ich den ASM-Code angeschaut hab ist mir klar geworden,
dass der Kompiler das was ich da schreibe anders Interpretiert bzw.
Sachen weckoptimiert die ich eigendlich brauch. Da kann man dann z.b.
mit valatile eingreifen.

von Markus (Gast)


Lesenswert?

ne, ich hab die Deklarierung jetzt in char s[2] geändert. Jetzt gehts
klaglos.

von Karl H. (kbuchegg)


Lesenswert?

> trotzdem finde ich es strange

Dann ist C nicht deine Sprache.
Genau das sind Dinge, die ganz alleine deiner Verantwortung
obliegen.
Weder könnte der Compiler so einen Fehler in allen Fällen
zu Compile-Zeit diesen Fehler detektieren noch wird (aus
Performance-Gründen) zur Laufzeit ein Check eingebaut.
Zur Laufzeit wäre es nämlich ebenso nicht möglich dieses
Problem in allen Fällen zuverlässig zu identifizieren.
In C ist ganz einfach deine Sorgfalt als Programmierer
gefragt und C entlässt dich nicht aus dieser Verantwortung.

> Ohne Optimizer ist der Compiler ohne Error oder Warning
> durchmarschiert und mit Optimizer kann dann die Meldung

Das liegt daran, dass auf deinem Compiler erst der Optimizer eine
Datenfluss-Analyse macht und es dabei erst auffält, dass da was
nicht stimmen kann.
Was du daraus mitnehmen solltest: Warnungen ernst nehmen.
Nicht umsonst gilt bei Industrieprogrammierern: Der Code
muss in allen Optimierungsleveln, fehler- UND warnungsfrei
comililiert werden können. Oft gibt es auch externe Tools
die den Code auch noch auf häufige Programmierfehler
durchchecken. 'lint' ist ein prominentes Beispiel dafür.

von Markus (Gast)


Lesenswert?

C ist auch nicht wirklich meine bevorzugte Sprache. Aber man wird ja
geradezu dazu gezwungen C zu können weil es die einzige Sprache ist
(von Assembler mal abgesehen) die es für fast jedes System gibt.

Mittlerweile hab ich schon gehört das beim Compilieren ohne Optimizer
auch einige Überprüfungen weggelassen werden um die Compilierung zu
beschleunigen. Daher können also solche Unterschiede kommen.

Ich gebe zu das ich weder ein C Freak bin noch unbedingt einer werden
will, aber ich will es gut genug können um damit über die Runden zu
kommen. Desshalb pack ich es hin und wieder mal aus

von A.K. (Gast)


Lesenswert?

"trotzdem finde ich es strange das der fehler ohne optimizer weder beim
compilieren noch bei der programmausführung auftritt."

Die Pointer-Variable ist bei dir nicht initialisiert. Sowas merkt der
Compiler, wie du ja gesehen hast. Aber das merkt er als Nebeneffekt
einer Datenflussanalyse. Die kostet Zeit und wird eigentlich mit dem
Ziel der Optimierung durchgeführt. Folglich kommt die Meldung nur bei
eingeschalteter Optimierung.

Und dass sich solcherart fehlerhafte Programme mit und ohne Optimierung
völlig anders verhalten ist ganz normal. Ohne Optimierung landen
Variablen immer im Speicher, mit Optimierung oft im Register, was bei
fehlender Initialisierung gänzlich andere Werte zur Folge hat.

von Markus (Gast)


Lesenswert?

Ja, wie gesagt. Ich hab mittlerweile erfahren das der Compiler ohne
Optimizer auch noch diverse andere Prüfungen weglässt. Man sollte also
hin und wieder mal einen Compilerlauf mit Optimizer machen um auch
solche Fehler frühzeitig zu finden

von Karl H. (kbuchegg)


Lesenswert?

Irgendwann machst du solch läppische Fehler von Haus aus
nicht mehr.
Denn dann hast du dir das Ritual eingelernt, dich bei einem
Pointer zuallererst mal zu fragen, ob und wo dieser Pointer
hinzeigt und wenn du das nicht mehr im Kopf hast zu überprüfen
ob mit dem Pointer alles mit rechten Dingen zugeht.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Man sollte also
> hin und wieder mal einen Compilerlauf mit Optimizer machen um auch
> solche Fehler frühzeitig zu finden

Meine ganz persönliche Meinung: man sollte immer mit Optimizer
compilieren, andernfalls debugst du einen komplett anderen
Maschinencode und debugst daher effektiv zweimal.  Gewöhn dich
stattdessen an die Artefakte der Optimierung (Variablen leben
nicht mehr über die gesamte Lebensdauer einer Funktion bzw.
wenn sie in Registern leben, werden diese anders wiederbelegt;
Der Programmablauf kann ,,springen'', da der Compiler Code
anders sortieren darf; nicht [mehr] benötigte Ergebnisse werden
auch nirgends mehr gespeichert) und debugge gleich das Endergebnis.

von A.K. (Gast)


Lesenswert?

"man sollte immer mit Optimizer compilieren"

Bei GCC/ARM nicht uneingeschränkt zu empfehlen. Der Optimizer
reorganisiert den Code derart, dass man bei Source-Code-Debugging
bisweilen wild im Quellcode herumspringt.

von Ronny (Gast)


Lesenswert?

Ist etwas Offtopic,aber naja...

Was ist mit dem aktuellen DevC++ für Windows?Eigentlich eine prima
Sache,nur leider ist es scheinbar nicht möglich einen Final-Build ohne
Debug-Infos zu machen.Die Einstellungen der IDE bezüglich Debuginfo
einbinden ignoriert das System scheinbar und wenn man den
Compiler/Linker von der Commandozeile aufruft das selbe.Ein kleines
Programm ist immer >450kb gross.Und selbst nach einem Strip-Durchlauf
ist die Exe noch 2xxKB gross.

Unter VC 6.0 konnte man immerhin ein Fenster mit einer 4kb Exe-Datei
erzeugen (mit etwas Linker-Tuning)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Der Optimizer
> reorganisiert den Code derart, dass man bei Source-Code-Debugging
> bisweilen wild im Quellcode herumspringt.

Logisch, RISC halt.  Deshalb ja auch mein "Get used to it.".  Du
debuggst eben sonst wirklich etwas völlig anderes, und damit
ist die Sache ziemlich wertlos.

Been there, done that.  Motorola m88k.  Auch eine echte RISC-
Maschine.  Da hüpfte der Zeiger im Emacs auch nur so auf und
ab im Quellcode.  Man gewöhnt sich dran, wenn man einmal weiß,
wie das zusammenhängt.  (In diesem Fall dürfte es das Ineinander-
schachteln von Speicher- und Registeroperationen sein, da ein
RISC-Prozessor typisch locker während eines Speicherzyklus noch
eine komplette Registerrechnung mit abarbeiten kann.)

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.