Ich habe eine große Anwendung, die in C + POSIX geschrieben ist. Es gibt viele Funktionen, die darin nie aufgerufen werden. Aufgrund der Größe des Codes ist es jedoch schwierig, sie manuell zu verfolgen.
Einige Leute haben vorgeschlagen, gcc mit -Wunused
und lto zu verwenden, aber es wurden keine verwendeten Funktionen zurückgegeben, während ich weiterhin einige manuell finde und entferne.
Ich denke also, ich brauche ein Code-Coverage-Tool, um das Programm zur Laufzeit zu analysieren. Peoples schlug mir gcov oder valgrind vor, aber ich konnte nicht finden, wie man damit eine Liste toter Funktionen ausdruckt. gcov allein ergab, dass nur 68 % der kompilierten Funktionen verwendet werden, aber ich habe keine Möglichkeit, sie aufzulisten.
Kennt jemand ein gutes Tool, und wenn ja, sagen Sie mir, wie genau ich es für diesen Zweck verwenden kann (ein Befehlszeilenbeispiel wäre willkommen) ?
Ich habe alle Funktionen entfernt, die im Quellcode nicht verwendet werden. Nur Funktionen wie diese verbleiben im Quellcode:
if(conditional statement) {
some stuff;
dead_function();
some_stuff;
}
Where conditional statement
ist zur Laufzeit nie wahr, und das Entfernen von dead_function()
würde zum Entfernen der Anweisung führen, um undefinierte Fehler zu vermeiden.
Da sich @user2284570 in der komfortablen Situation befindet, 100 % der Anwendungsfälle durch Tests abzudecken, wird die dynamische Codeanalyse die Antwort liefern. In anderen Fällen würde das Entfernen von Funktionen, deren Aufrufen und Bedingungen eine gründliche Überprüfung erfordern.
Jedes Codeabdeckungstool meldet die Funktionsabdeckung in der einen oder anderen Form. Der Hauptkritikpunkt scheint die Meldung der genauen Position ungenutzter (hier: toter) Funktionen zu sein. Ich kann nicht für andere Tools sprechen, aber das unseres Unternehmens verfügt über eine Berichtsoption im Textformat, die Platzhalter für Quelldateinamen und Zeilendaten enthält. Da nach einem konkreten Kommandozeilenbeispiel gefragt wurde hier eines:
$ csgcc -o myapp mycode.c
$ ./myapp --run-all-tests
$ cmcsexeimport -m myapp.csmes -e myapp.csexe --title=mytests
$ cmreport --function-coverage -m myapp.csmes --format-unexecuted='%f:%l'
Dadurch werden die toten Funktionsorte wie folgt gedruckt:
mycode.c:101
mycode.c:213
mycode.c:1032
Ein ortsansässiger Universitätsstudent verfasste detailliertere Anweisungen für diesen Ansatz.
Nachdem Sie ungenutzte Funktionen eliminiert haben, sollten Sie auch die Zweigabdeckung analysieren und überflüssige if()-Anweisungen und andere entfernen. Hüten Sie sich nur vor Nebeneffekten ausgewerteter Ausdrücke. Aber zum Glück erkennt Ihre perfekte Codeabdeckung Regressionen.
Sie können splint
mit dem alluse
Flag nach nicht verwendeten Funktionen suchen, aber ich persönlich würde verwenden doxygen
, um eine Aufrufzuordnung zu erstellen - alle Funktionen, die keine Eltern haben, werden wahrscheinlich nicht verwendet - suchen Sie einfach nach Funktionen, die sich in Tabellen von Funktionen befinden, die möglicherweise nicht direkt aufgerufen werden aber Dinge wie Zustandsmaschinen könnten aus dem Tabellenindex aufgerufen werden.
Doxygen ist ein unschätzbares Werkzeug für den Umgang mit großen Codebasen und es lohnt sich auf jeden Fall, seine Verwendung zu lernen, es ist kostenlos und für mehrere Plattformen verfügbar, es neigt auch dazu, die Dokumentation Ihres Codes zu fördern, während Sie fortfahren.
Im Fall von Code, der aufgerufen wird, aber nur von unerreichbarem Code, müssen Sie ein vollständiges statisches Analysetool wie LDRA (kostspielig) verwenden, das Sie auf unerreichbaren Code hinweist. In diesem Fall ist es besser, zuerst den gesamten nicht erreichbaren Code zu entfernen und dann nach nicht aufgerufenen Funktionen zu suchen. Alternativ benötigen Sie eine Testsuite, von der Sie sicher sind, dass sie 100 % der Funktionalität ausführt. Dann können Sie einen Profiler oder ein Abdeckungstool wie gcov in Ihrem Programm verwenden, während Sie Ihre Testsuite ausführen. Wenn Ihr Test Ihre gesamte Funktionalität ausgeführt hat und Sie Teile mit einer Abdeckung von 0 % haben, werden sie nicht aufgerufen , aber Sie müssen dann die Aufrufe finden, die nicht erreichbar sind, und diesen Code entfernen, damit sich der Linker trotzdem nicht beschwert.
Um Ihre überarbeitete Frage zu beantworten: Wenn Sie Ihren gesamten Code mit gcc -fprofile-arcs -ftest-coverage
festgelegten Optionen kompilieren und dann eine Reihe von Tests ausführen, von denen Sie sicher sind, dass sie alle Funktionen und alle Möglichkeiten abdecken (möglicherweise über mehrere Durchläufe hinweg).
Das gcov
Dienstprogramm erwartet, dass Sie einen Teil der Arbeit erledigen - es hat nicht nur eine Option für "Sagen Sie mir, was nicht aufgerufen wurde", sodass Sie die Funktionen finden müssen, die nicht aufgerufen wurden.
Sie können mit gcov
der --function-summaries
Option für jede Quelldatei eine Reihe von Ausgabedateien generieren, die Funktionszusammenfassungen enthalten. Suchen Sie nach Dateien , die entweder never
oder enthalten 0%
, um die nicht ausgeführten Funktionen zu finden.
Ich würde vorschlagen, entweder eine Funktion hinzuzufügen, von der Sie wissen, dass sie niemals aufgerufen wird, oder eine zu kennen, die Sie noch nicht entfernt haben - so können Sie sehen, wie die Ausgabe aussieht - Sie können sie dann verwenden grep
, um sie alle zu finden.
Ihr nächster Schritt besteht darin, grep
die gcov
Ausgabe für alle Stellen zu verwenden, an denen diese Funktionen in Ihrem Code vorhanden sind. Sie sollten Ausführungszähler von 0 für den gesamten Zweig sehen, der den Aufruf enthält . Dies gibt Ihnen einen guten Ausgangspunkt um entweder Ihre Tests zu erweitern - für Anwendungsfälle, die Sie verpasst haben - oder um Code zu entfernen.
Gilles 'SO- hör auf, böse zu sein'
dead_function
wird verwendet), sondern toter Code. Das erfordert ganz andere Techniken! Beachten Sie, dass die Laufzeitanalyse nur Code findet, der zufällig nicht in einer bestimmten Ausführung des Programms ausgeführt wurde – dieser Code kann unter anderen Umständen live sein.Benutzer2284570
Ira Baxter
Benutzer2284570
Steve Barnes
Mawg sagt, Monica wieder einzusetzen
Benutzer2284570
Benutzer2284570
Steve Barnes
printf(__func__);
als erste Zeile hinzu, in gcc wird der Name der Funktion bei jedem Aufruf gedruckt - führen Sie Ihre Testerfassungsausgabe aus, dann wird jeder Name, der nicht in der Ausgabe enthalten ist, nicht aufgerufen.Benutzer2284570
Steve Barnes
Steve Barnes
Benutzer2284570
Steve Barnes
Mawg sagt, Monica wieder einzusetzen
Benutzer2284570
Mawg sagt, Monica wieder einzusetzen