|
|
CompilerfehlerNichts ist perfekt, und auch ein Compiler ist es nicht. Er kann also Fehler haben, sogenannte Compilerfehler oder Compiler-Bugs. Erfahrungsgemäß entpuppen sich mindestens 99% der berichteten Compilerfehler als Fehler in der Anwendung, die ihre Ursache oft in einem nicht ausreichenden Verständnis der verwendeten Programmiersprache haben. Bevor also ein angeblicher Compilerfehler berichtet wird, sollte man sicher sein, dass nicht einer der folgenden, häufigen Programmierfehler vorliegt.
[Bearbeiten] Die häufigsten Nicht-FehlerHäufig führen Missverständnisse über oder Wissenslücken in der Programmiersprache zu Fehlinterpretationen des Compilerverhaltens als Compilerfehler. Die häufigsten Irrtümer sind: [Bearbeiten] Compiler-OptimierungenEin optimierender Compiler kann
Häufig sorgt das Wegoptimiern von Warteschleifen für Verwirrung. Code wie
hat keine Wirkung weil i nicht weiterverwendet wird und kann daher entfernt werden! Aufgabe eines Optimizers ist es ja gerade, Programme schneller zu machen und daher sind solche nutzlosen Zeitfresser für ihn ein gefundenes Fressen. Alles in allem darf ein C/C++-Compiler den Code so optimieren, daß lediglich die Nebeneffekte der Funktionen unverändert bleiben. Nebeneffekte sind z.B. das Verändern globaler Variablen. Beispiel:
int z;
int foo (int x)
{
int a = 1;
int b;
// b (und damit a) werden im weiteren Verlauf zwar noch verwendet, aber
// der Wert in b ist dem Compiler bekannt. Er braucht also keine Variable
// "b" anzulegen. b ist also in einem Debugger u.U. nicht mehr vorhanden.
b = a+3;
z = x;
// z ist nicht volatile und wird mit 0 beschrieben. Die vorangegangene
// Zuweisung darf also wegoptimiert werden.
z = 0;
// Welchen Wert hat b? "return b" ist gleichbedeutend mit "return 4".
return b;
}
In Summa hat die obige Funktion also den gleichen effekt wie
int z;
int foo (int x)
{
z = 0;
return 4;
}
[Bearbeiten] Interrupt-ProgrammierungBeim Datenaustausch zwischen Interrupt-Routinen und Programm ist zu beachten:
[Bearbeiten] Position von const und volatile bei PointernEin
hat eine andere Bedeutung und damit auch ein anderes Optimierungsverhalten als ein
Im ersten Fall ist das, worauf der Pointer zeigt, volatile. Im zweiten Fall ist der Pointer selbst volatile. Ist sowohl der Pointer als auch das Ziel des Pointers volatile, so lautet die Definition
In Gedanken trennt man die Definition beim "*" und ordnet das volatile dem jeweiligen Teil der Definition zu. [Bearbeiten] (Implizite) Typ-Umwandlungen und BereichsüberläufeWenn Zwischenergebnisse nicht in den Wertebereich passen, dann werden die übergelaufenen Bits entfernt. Das kann auch dann geschehen, wenn das Endergebnis nicht überläuft. Bei Rechnung mit Vorzeichen ist das Ergebnis bei Überlauf auch in den unteren Bits undefiniert, nur bei Rechnung ohne Vorzeichen ist das Verhalten bei Überlauf klar definiert. [Bearbeiten] StacküberlaufDer Stack wächst in den Bereich normaler Daten und überschreibt diese — oder umgekehrt. Das Programm zeigt unvorhersagbares Verhalten oder stürzt komplett ab. [Bearbeiten] Aussagekräftige FehlerbeschreibungWenn es sich wirklich um einen Compilerfehler handelt, bzw. die Hinweise darauf sich verdichten, ist es sinnvoll, z. B. in einem Forum nachzufragen, um Hilfe und Ratschläge zu bekommen. Manchmal ist ein Fehler schon bekannt und es kann gesagt werden, wie der Fehler umschifft (eng. Workaround) werden kann. Dazu ist es notwendig, einen Testfall zu erstellen, damit andere den Fehler nachvollziehen und beurteilen können. Compiler sind hochkomplexe Programme, und ohne die Eingabe — also ohne die Quelldatei, die den Fehler hervorruft — sind praktisch keine Aussagen möglich, ob es sich bei einem Phänomen um einen Compilerfehler handelt oder nicht.
[Bearbeiten] Bekannte Fehler
[Bearbeiten] Weblinks
|