Toter CodeToter Code (englisch dead code) ist in der Programmierung ein Begriff für Teile eines Computerprogramms, „die an keiner Stelle im Programm verwendet werden“.[1] In erweitertem Sinn kann toter Code als Sonderform redundanten Codes (= „überflüssig“) betrachtet werden. Toter Code kann Anweisungen/Befehle enthalten oder sich auf nicht verwendete Datendeklarationen beziehen. Unerreichbarer Code ist ein Programmteil, der durch keinen möglichen Kontrollfluss erreicht und deshalb erst gar nicht ausgeführt werden kann; auch hierbei wird mitunter von totem Code gesprochen. BedeutungAlle Formen toten Codes gelten aus verschiedenen Gründen als unerwünscht bzw. Mangel in der Softwarequalität. Je nach Situation kann toter Code auch bewusst entstehen: Er soll beispielsweise einen vorläufigen oder ehemaligen Quelltextteil konservieren. Häufig liegt jedoch auch ein Programmfehler vor, dessen Entdeckung ein Ziel beim Softwaretest ist. Obwohl die Ergebnisse von totem Code nie verwendet werden, kann er Ausnahmebehandlungen auslösen oder globale Status beeinflussen. So kann eine Codeänderung die Programmausgabe verändern und unbeabsichtigte Programmfehler verursachen. In solchen Fällen ist es umstritten, ob weiterhin von totem Code gesprochen werden kann. Beispielint foo (int x) {
int y = 100 / x; // toter Code, da y nicht verwendet wird
int z = x * x; // redundanter Code zu 2 Zeilen weiter unten
if (z >= 0) { // unnoetiger Code, da die Abfrage immer wahr ist
return x * x; // redundanter Code zu 2 Zeilen weiter oben
}
return -1; // unerreichbarer Code, da z immer >= 0 ist
}
GründeToter Code kann unter anderem entstehen durch
In den letzten fünf Fällen ist der derzeit unerreichbare Code eine Altlast, d. h. Code, der früher sinnvoll war, aber nicht mehr benötigt wird. Beispiel Oft wird absichtlich toter Code erzeugt, um Ausgaben während der Programmentwicklung später zu deaktivieren: int main()
{
#define DEBUG 0
int a = 3;
// ...
if (DEBUG)
printf("%d\n", a);
// ...
return a;
}
Während der Entwicklungsphase kann hier der Wert der Variablen a ausgegeben werden, falls das Makro DEBUG auf einen Wert ungleich Null (wahr) gesetzt wird. Wenn diese Kontrollausgabe nicht mehr benötigt wird, setzt man den Wert auf 0 und der Präprozessor erkennt und entfernt das nun tote Stück Code. AnalyseToten Code zu entdecken ist eine Form von statischer Codeanalyse und benötigt eine genaue Analyse der Ablaufsteuerung, um den Code unabhängig von den Variablen und anderen Laufzeitbedingungen zu finden. Mit Hilfe geeigneter Analysewerkzeuge kann ein Großteil toter und unerreichbarer Codeteile gefunden werden. In einigen Sprachen (wie z. B. Java) sind einige Formen von unerreichbarem Code ausdrücklich verboten und führen zu Kompilierungsfehlern. In großen Softwareprojekten ist es manchmal schwierig, toten Code zu erkennen und zu entfernen, insbesondere wenn ganze Module davon betroffen sind. Der Testgerüstbau kann solchen Code als noch „lebendig“ zeigen, und es kann sogar sein, dass aus vertraglichen Gründen der irrelevante Code geliefert werden muss.[2] In einigen Fällen ist ein praktischer, nicht allzu aufwändiger Ansatz eine Kombination von einfachen Unerreichbarkeitskriterien und die Verwendung von einem Profiler, um komplexe Fälle zu bearbeiten. Mit Profiling kann man nicht die Unerreichbarkeit von Code beweisen. Es ist aber eine gute heuristische Methode, um potenziell unerreichbaren Code zu entdecken. Wird einmal ein Codeteil als suspekt gesehen, können andere Methoden wie z. B. wirksamere Codeanalysewerkzeuge verwendet oder die Analyse von Hand durchgeführt werden. Dadurch kann man dann entscheiden, ob der gefundene Codeteil wirklich unerreichbar ist oder nicht. OptimierungSeit Mitte der 1990er Jahre ist es Stand der Technik, dass Compiler und Linker unbenutzte Codeabschnitte erkennen und entfernen. Diese Optimierungstechnik bezeichnet man als dead code elimination. Seit Mitte der 2010er Jahre haben äquivalente Techniken in IDEs (Anzeige von unbenutzten Code schon beim Editieren) und in Debugger (Code, der im aktuellen Durchlauf nicht mehr erreicht werden kann, wird beispielsweise abgedunkelt) Einzug gehalten. Die korrekte, redundanzfreie Umsetzung des oberen Beispiels würde folgendermaßen aussehen: int foo (int x) {
return x*x;
}
Die Optimierung toten Codes funktioniert bei allen Arten toten Codes ähnlich, meist durch einfaches Entfernen der betreffenden Codestellen. Bei der Entfernung von totem Code ist besondere Vorsicht geboten, da toter Code Seiteneffekte haben kann, die aus dem Code selbst nicht erkennbar sind. Compileroptimierungen sind typischerweise konservative Ansätze, um toten oder unerreichbaren Code zu entfernen. Ist eine Mehrdeutigkeit bezüglich Programmverhalten vorhanden, wird der Code nicht entfernt. Die Optimierung während der Kompilierung wird Dead code elimination genannt. Sie kann für toten Code durch Variablenanalyse, für unerreichbaren Kode mit Datenflusskontrolle gemacht werden. Der Code kann auch durch Transformationen, die der Compiler durchführt, unerreichbar werden, wie z. B. die sogenannte common subexpression elimination (Entfernen gemeinsamer Teilausdrücke). In der Praxis hat die Ausgereiftheit der Analyse einen entscheidenden Einfluss auf den Anteil des gefundenen unerreichbaren Codes. Z. B. kann durch constant folding und einfache Flussanalyse gezeigt werden, dass der Funktionsaufruf int i = 2 + 1;
if (i == 4)
foo();
Einer vollständigen Analyse zur Kompilierungszeit sind jedoch theoretische Grenzen gesetzt, die eng mit der Entscheidbarkeitsproblematik der theoretischen Informatik verbunden sind. Öffentliche WahrnehmungIm November 2010 veröffentlichte Microsoft eine neue Version des Internet Explorers, der scheinbar alle anderen Browser in puncto JavaScript-Geschwindigkeit weit hinter sich ließ. Es stellte sich jedoch schon bald heraus, dass Microsoft eine spezielle Implementation der dead code elimination nutzte, um sich an die Spitze eines bekannten JavaScript-Benchmarks zu katapultieren. In anderen Benchmarks waren die Resultate eher im Mittelfeld.[3] Literatur
Weblinks
Tools zum Auffinden toten/unerreichbaren Codes
Einzelnachweise
|