Hallo,
welchen Parameter muss ich verwenden, damit mich gcc warnt, wenn globale
Variablen nicht verwendet werden? Habe irgendwie auf die Schnelle nichts
gefunden... -Wall -Wextra hilft jedenfalls auch nicht.
Schreib "static" davor, das erhöht du Chance, daß die Warnung kommt.
(dann ist nämlich klar, daß die Variable nicht "extern" benutzt wird.
BTW, ein guter Linker link keine Objekte dazu, die keiner braucht.
Carl D. schrieb:> BTW, ein guter Linker link keine Objekte dazu, die keiner braucht.
Dann ist er anders eine Fleischwarenfachverkäuferin. Die fragt:
"Darf's von der fetten, groben Variable noch ein Byte mehr sein?"
MfG Paul
Carl D. schrieb:> BTW, ein guter Linker link keine Objekte dazu, die keiner braucht.
Wenn ein globales Objekt Teil einer aus anderen Gründen verwendeten
Section ist, dann kann der Linker es nicht weglassen. Auf explizit
initialisierte globale Variablen und auf Funktionen trifft das i.A. zu.
Bei nicht initialisierten globalen Variablen kann es je nach Umgebung
anders sein.
Dies gilt jedenfalls im klassischen Modell von Compiler/Assemblern, die
Objectfiles bestehend aus je einer Code/Data/... Section erzeugen.
In GCC gibt es Optionen in Compiler und Linker, um alle Objekte in
individuellen Sections unterzubringen und deshalb weglassen zu können.
Alterativ geht das auch mit Übersetzung des gesamten Programms in einem
Schritt.
Hallo,
ich gehe davon aus, du benutzt GCC.
Also wenn die Variable im C Modul global ist und nicht
1
static
davor steht, dann geht der Compiler davon aus, die wird auch von einem
anderen Modul benutzt.
Wenn du
1
static
davor schreibst, ist das die Voraussetzung, dass der Compiler zumindest
was sagen kann.
Der Linker kann mit folgender Anweisung unreferenzierte Funktionen und
Daten beim Linken weglassen:
- beim Compileren folgende optionen dazunehmen: -ffunction-sections
-fdata-sections
- beim Linken: -Wl,--gc-sections
Bei mir warnt der GCC 4.8 und 4.9 zuverlässig vor unbenutzten:
Ich bin dabei, eine größere Anwendung "aufzuräumen". Die globalen
Variablen stehen in den .h-Dateien. Da ist nix mit static, weil es
globale Variablen sind. Viele werden aber nicht weiter verwendet. Ich
muss wissen, welche.
Im Prinzip das gleiche brauche ich dann noch für Funktionen.
A. K. schrieb:> Bei nicht initialisierten globalen Variablen kann es je nach Umgebung> anders sein.
Ich dachte die gibt es laut C-Standard nicht? Wenn mich nicht alles
täuscht, sind globale Variablen per Default zu Null initialisiert.
Mark B. schrieb:> Ich dachte die gibt es laut C-Standard nicht? Wenn mich nicht alles> täuscht, sind globale Variablen per Default zu Null initialisiert.
Korrekt. Ich hatte mich oben direkt davor aber ausdrücklich auf explizit
initialisierte globale Variablen bezogen. Der Folgesatz bezieht sich
daher auf nicht explizit initialisierte Variablen.
Je nach Compiler werde die u.U. einzeln als sogenannte "commons" an den
Linker durchgereicht (Fortran lässt grüssen). Dann sind sie im
Objectfile in keiner Section alloziert, sondern tauchen nur in der
Symboltable auf. Erst der Linker sammelt die ein und platziert sie. Er
könnte sie daher auch problemlos weglassen, wenn er unabhängig davon die
Referenzierung erfasst.
Charakteristisch für solche Umgebungen ist, dass man sowas wie "int
global_variable;" in mehreren Übersetzungseinheiten verwenden kann, ohne
im Linker auf einen Fehler zu laufen. Obwohl eigentlich die Regel gilt,
dass dies nur in einer einzigen Übersetzungseinheit zulässig ist.
In der Zeit hättest dir schon längst ein perl Skript geschrieben, dass
das für dich erledigt.
Wenn du ein größeres Projekt hast, dann hast du auch dort die Finger
drin. Dann solltest du auch in der Lage sein, dir ein einfaches Skript
mit regex zu schreiben, dass dir genau diese Aufgabe löst.
1. Schritt: In allen *.h alle globalen Variablen suchen und in einen
hash speichern
2. in allen *.c Dateien genau diese Daten suchen. Sollte der Name
verwendet werden, dann kommt er aus der Liste raus, sonst bleibt er
drin. Evtl. noch auf Namespaces achten, allerdings sollten Verletzungen
dessen in "größeren" Projekten sowieso nicht auftauchen.
Fritzchen schrieb:> Ich bin dabei, eine größere Anwendung "aufzuräumen". Die globalen> Variablen stehen in den .h-Dateien.
Variblen solltest du nur in einem Modul definieren.
1
intvariable;
Im headerfile sollte nur die Deklaration stehen, damit C Module den Typ
kennen.
1
externintvariable;
Wenn du jetzt ohne Compilerfehler die Variable im .h File weglassen
kannst, dann wird die Variable nur in dem Modul geraucht, wo sie auch
definiert ist.
Grüsse.
Adib schrieb:> Wenn du jetzt ohne Compilerfehler die Variable im .h File weglassen> kannst, dann wird die Variable nur in dem Modul geraucht, wo sie auch> definiert ist.
Und wenn man in diesem Szenario andererseits die Definition weglässt und
der Linker still bleibt, dann wird sie nirgends verwendet.
Zuverlässig ist das doch alles nicht. Es kann ja auch sein, dass die
Variable nur geschrieben, aber nie gelesen wird, z.B. wenn sie in
irgendeiner Init-Funktion einmalig einen Wert bekommt, aber danach nie
mehr verwendet wird. Dann kann sie auch weg.
A. K. schrieb:> Ich hatte mich oben direkt davor aber ausdrücklich auf explizit> initialisierte globale Variablen bezogen. Der Folgesatz bezieht sich> daher auf nicht explizit initialisierte Variablen.
Soweit ich weiß unterscheiden gcc und ld aber nicht zwischen implizit
und explizit mit 0 initialisierten Variablen. Nur Initialisierungswerte,
die von 0 verschieden sind, werden anders behandelt.
> Je nach Compiler werde die u.U. einzeln als sogenannte "commons" an den> Linker durchgereicht (Fortran lässt grüssen). Dann sind sie im> Objectfile in keiner Section alloziert, sondern tauchen nur in der> Symboltable auf.
Ich kenne das so, dass sie in die Section .bss kommen und dann vom
Startup-Code im memset-Stil alle am Stück mit 0 initialisiert werden.
Fritzchen schrieb:> Hmmmmm... das heißt, gcc kann das gar nicht???
Der gcc kann es gar nicht können.
A. K. schrieb:> Charakteristisch für solche Umgebungen ist, dass man sowas wie "int> global_variable;" in mehreren Übersetzungseinheiten verwenden kann,> ohne im Linker auf einen Fehler zu laufen.
Es gibt sogar keinen Fehler, wenn in einem Modul "int global_variable;"
steht und in einem anderen "float global_variable;".
Einen Fehler gibt es in dem Fall erst dann, wenn modulübergreifend
optimiert wird (z.B. LTO per -flto) oder per -fno-common auf COMMON
verzichtet wird.
Fritzchen schrieb:> Ich bin dabei, eine größere Anwendung "aufzuräumen". Die globalen> Variablen stehen in den .h-Dateien. Da ist nix mit static, weil es> globale Variablen sind. Viele werden aber nicht weiter verw
Dann kommentiere sämtliche extern-Deklarationen in den Header-Dateien
aus. Der Compiler sagt Dir dann, welche er braucht. Die aktivierst Du
dann wieder, die anderen löschst Du.
Der einfachste Tip wurde ja schon genant: Die Definitionen der
fraglichen Variablen auskommentieren, und schauen, welche dann vom
Linker vermisst werden. Bei Funktionen geht es prinzipiell genauso.
Hilfreich Hinweise gibt dir da auch Doxygen. Das kann dir Caller und
Calles auflisten.
Oder nutz einen vernünftigen Editor/IDE, wie z.B. QtCreator. Der findet
alle Stellen, an denen eine Variable oder eine Funktion verwendet wird,
mit einem Mausklick.
Oliver
Rolf M. schrieb:> Soweit ich weiß unterscheiden gcc und ld aber nicht zwischen implizit> und explizit mit 0 initialisierten Variablen. Nur Initialisierungswerte,> die von 0 verschieden sind, werden anders behandelt.
Vielleicht wird irgendein Compiler oder eine Version eine explizite
Initialisierung mit 0 zu einer impliziten Initialisierung machen. GCC
4.7 und GCC 4.8 tun dies aber offenbar nicht automatisch.
> Ich kenne das so, dass sie in die Section .bss kommen
Aber erst im Linker. Der Compiler (einer solchen Umgebung) erzeugt nur
einen "common" Eintrag in der Symboltabelle, mit der zu allozierenden
Grösse. Wenn dieser Name anderswo als echte Definition auftaucht (unten
"D"), dann wird der "C" Eintrag effektiv ignoriert.
A. K. schrieb:>> Soweit ich weiß unterscheiden gcc und ld aber nicht zwischen implizit>> und explizit mit 0 initialisierten Variablen. Nur Initialisierungswerte,>> die von 0 verschieden sind, werden anders behandelt.>> Vielleicht wird irgendein Compiler oder eine Version eine explizite> Initialisierung mit 0 zu einer impliziten Initialisierung machen. GCC> 4.7 und GCC 4.8 tun dies aber offenbar nicht automatisch.
Korrektur: Beides ist ein wenig richtig und ein wenig falsch. :-)
Explizite Initialisierungen mit 0 werden erkannt, werden aber nicht wie
bei impliziten Initialisierungen zu Commons, sondern landen explizit in
.bss statt .data (obiger .s Code ist nicht korrekt). Damit entfällt der
Platz im Image, aber es sind echte harte Definitionen, keine schwachen
Definitionen wie implizit initialisierte Variablen.
1
.bss
2
explicit_int:
3
.zero 4
1
.data
2
explicit_int:
3
.long 1
Während man also in einer solchen Umgebung
file1.c: int var; //C
file2.c: int var; //C
schreiben kann, geht zwar auch
file1.c: int var; //C
file2.c: int var = 0; //D
aber nicht
file1.c: int var = 0; //D
file2.c: int var = 0; //D
In Eclipse kann man sich (wenn der Cursor auf einem Bezeichner steht)
mit Ctrl+Alt+H die Aufrufer- und Aufrufgraphen jeweils in
Baumdarstellung zeigen lassen.
Und obwohl der Menüpunkt "Call Hierarchy" eigentlich zunächst vermuten
lässt es ginge nur für Funktionen funktioniert der Aufrufergraph
ebensogut mit einer globalen Variablen als Wurzel. Dann siehst Du in
welchen Funktionen die fragliche Variable verwendet wird.
Sehr praktische Sache das.
Und um mich meinem Vorredner anzuschließen: Doxygen (mit allen Optionen
aktiviert, vor allem die Graphen) drüberlaufen lassen gibt auch eine
stellenweise sehr hilfreiche Sicht auf die Struktur des Gesamtgebildes.
Bernd K. schrieb:> In Eclipse kann man sich (wenn der Cursor auf einem Bezeichner steht)> mit Ctrl+Alt+H die Aufrufer- und Aufrufgraphen jeweils in> Baumdarstellung zeigen lassen.
Danke für den Tipp!