Forum: Compiler & IDEs GCC: Warnung vor "unused global variable" aktivieren?


von Fritzchen (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Das wird allenfalls der Linker feststellen, nicht aber der Compiler. 
Siehe also bei dessen Flags.

von Carl D. (jcw2)


Lesenswert?

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.

von Paul B. (paul_baumann)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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.

von Adib (Gast)


Lesenswert?

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:
1
static int wert = 2;

Schau auch mal -funused-data bei 
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Grüße, Adib.

von Fritzchen (Gast)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Eine Möglichkeit ist des erwähnte --gc-sections etc. und ein Map-File 
vom Linker erstellen zu lassen.  Darin siehst du dann, was entsorgt 
wurde.

von Mark B. (markbrandis)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von -.-.- (Gast)


Lesenswert?

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.

von Fritzchen (Gast)


Lesenswert?

Hmmmmm... das heißt, gcc kann das gar nicht???

von Adib (Gast)


Lesenswert?

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
int variable;
Im headerfile sollte nur die Deklaration stehen, damit C Module den Typ 
kennen.
1
extern int variable;

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von ukw (Gast)


Lesenswert?

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.

von Oliver S. (oliverso)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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.
1
extern int      extern_int;
2
int             implicit_int;
3
int             explicit_int = 0;
1
file.s:
2
        .comm   implicit_int,4,4
3
        .globl  explicit_int
4
        .data
5
        .align 4
6
explicit_int:
7
        .zero   4
1
file.o:
2
0000000000000000 D explicit_int
3
                 U extern_int
4
0000000000000004 C implicit_int

von (prx) A. K. (prx)


Lesenswert?

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

von Bernd K. (prof7bit)


Lesenswert?

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.

von Walter T. (nicolas)


Lesenswert?

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!

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.