Global, Modulglobal, Lokal
-
Hallo Freunde,
ich beschäftige mich momentan mit Speicherklassen und habe ein paar Frage an euch. Mir ist natürlich durchaus bekannt, was der Unterschied zwischen einer (programm)globalen, modulglobalen und lokalen Variable ist. In meinem Lehrbuch wird jedoch momentan über den Speicherklassenspezifizierer "extern" geredet.Angenommen ich habe eine .cpp Datei in der ich eine globale Variable deklariere:
#include <iostream> ... int global; ...
dann ist diese Variable ja nur in dieser Unit bekannt (soweit ich keine anderen eingebunden habe).
Wenn ich jetzt in der einer zweiten Unit auf diese gloabel Variable zugreifen möchte, dann gibt es doch zwei Möglichkeiten:
1.) Ich inkludiere die Unit (?).
2.) Ich benutze den Speicherklassenspezifizierer "extern".Kann man "extern" wie einen Parameter ansehen, über welchen die Variable an die zweite Unit übergeben wird oder wie funktioniert das?
[edit]: Ich lese gerade: Eine extern-Deklaration ist lediglich ein Verweis auf ein Objekt und sollte daher kein Initialisierung erhalten.
Was ist hier mit Verweis gemeint (kein Zeiger...).Außerdem: Jeder weiß, dass man mit globalen Variablen sparsam sein sollte, doch frage ich mich warum. Weil sie erst am Programmende zerstört werden?
Vielen Dank für eure Hilfe
lg, freakC++
-
freakC++ schrieb:
Außerdem: Jeder weiß, dass man mit globalen Variablen sparsam sein sollte, doch frage ich mich warum. Weil sie erst am Programmende zerstört werden?
Wegen der doppelten Namensgebung. Meist behandelt dein Code ein bestimmtes Thema, d.h., dass die Dopplung von Namen / Bezeichnungen sogar relativ wahrscheinlich ist. Passiert mir dauernd. Ich denke mir nicht tausend Variablen aus, sondern nehme öfter mal die gleichen. Aber eben nur lokal. Würde ich globale Variablen nutzen hätte ich Stress
-
Hallo,
vielen Dank schonmal für deine Antwort. Wie sieht es denn nun mt dem Wörtchen "extern" aus?
lg, freakC++
PS.: Wir hatten eben gleiche viele Threads
-
freakC++ schrieb:
Wenn ich jetzt in der einer zweiten Unit auf diese gloabel Variable zugreifen möchte, dann gibt es doch zwei Möglichkeiten:
1.) Ich inkludiere die Unit (?).
2.) Ich benutze den Speicherklassenspezifizierer "extern".Zu 1) Eben nicht. Dann steht der Name in jeder Übersetzungseinheit für eine andere Variable.
Zu 2) Genau so.Warum man globale Variablen vermeiden sollte: Sie machen es extrem schwer den Code hinterher zu verstehen, weil nicht klar ist, wann und wo Änderungen durchgeführt werden.
-
freakC++ schrieb:
Angenommen ich habe eine .cpp Datei in der ich eine globale Variable deklariere:
#include <iostream> ... int global; ...
dann ist diese Variable ja nur in dieser Unit bekannt (soweit ich keine anderen eingebunden habe).
Hier definierst Du eine Variable mit externer Bindung. Das heißt, es wird Speicher reserviert. Wenn Du in einer zweiten Übersetzungseinheit (ÜE) einer neuen Varialben denselben Namen gibst und die beiden ÜEs verlinkst, ist das eine Verletzung der "Eine-Definition-Regel" --> Der Linker wird sich beschweren, dass "global" zweimal definiert worden ist. Obwohl diese Variable vielleicht nicht anderen ÜEs "bekannt" ist, wird der "Name verbraucht", weil die Variable eine externe Bindung besitzt.
Gibst Du in anderen ÜEs nur folgendes an:
extern int global;
deklarierst Du nur eine Variable mit externer Bindung. Du sagst dem Compiler also, dass es eine Variable namens "global" mit externer Bindung gibt, die in irgendeiner anderen ÜE definiert wird (bzw werden sollte).
Wenn Du Variablen mit interner Bindung haben möchtest, gibt es mehrere Möglichkeiten:
const int foo1 = 23; // Konstanten haben automatisch interne Bindung static int foo2; // "static" bedeutet in diesem Kontext "interne Bindung", // ist also das Gegenteil von "extern" in diesem Fall namespace { int foo3; // foo3 im anonymen Namensraum hat auch "interne Bindung" }
Der Unterschied zwischen interner und externer Bindung ist der, dass Objekte und Funktionen mit interner Bindung nicht über ihre Namen in anderen ÜEs "sichtbar" sind -- auch dann nicht, wenn man in den anderen ÜEs entsprechende Deklarierungen benutzt. Namen von Objekten und Funktionen mit externer Bindung beziehen sich immer auf dasselbe Objekt bzw dieselbe Funktion. Es sollte i.d.R. genau eine Definition geben. Ausnahmen gibt es aber auch: Klassendefinitionen, Inline-Funktionen und Funktions-Templates. Siehe "one definition rule" in jedem guten C++ Buch.
Konstanten mit externer Bindung gibt es übrigens auch:
datei1.cpp:extern const int dings = 42; // Definition
datei2.cpp:
extern const int dings; // Deklaration
Hier bezieht sich der Name "dings" wieder auf ein und dieselbe Variable (da externe Bindung).
Ich hoffe, das hat etwas geholfen. Ich habe da auch erst nicht durchgeblickt. Wichtinge Konzepte sind:
- Übersetzungseinheit (engl: "translation unit" -- bei
#include "soundso"
passiert wirklich nur eine einfache Textersetzung beim Preprocessor! All das, was der Preprocessor für ein *.cpp ausspuckt ist quasi die "Übersetzungseinheit") - externe/interne Bindung (engl: "external/internal linkage")
Gruß,
SP
- Übersetzungseinheit (engl: "translation unit" -- bei
-
Hallo,
vielen Dank für den langen Post, Sebastian Pizer. Du hast mir dabei sehr geholfen. Nun zweifel ich jedoch, dass ich den Unterschied
zwischen Deklaration und Definiton begriffen habe. Ich dachte, dass eine Deklaration die "Bekanntmachung" der Variablen ist und
eine Definition die erste Wertzuweisung ist.Beispiel
int zahl; //Deklaration int nummer = 4; //Definition
Liege ich da falsch? Sonst verstehe ich nicht, warum "int global" eine Definition sein soll.
Vielen Dank für eure Hilfe
lg, freakC++
-
freakC++ schrieb:
Ich dachte, dass eine Deklaration die "Bekanntmachung" der Variablen ist
nicht nur Variablen, auch Klassen, Funktionen, Klassen-Templates und Funktions-Templates.
freakC++ schrieb:
und eine Definition die erste Wertzuweisung ist.
Nein. Das verwechselst Du mit Initialisierung. Was genau eine Definition bedeutet, hängt davon ab, was definiert wird. Bei Variablen auf Namensraumebene führt eine eine Definition dazu, dass der Compiler für diese Variable Speicher reserviert. Und das sollte bei einer Variablen oder "normalen" Funktion mit externer Bindung in nur genau einer ÜE passieren. ("normal" = kein Inline und kein Template)
class Klasse; // Deklaration von Klasse, // Klasse ist nun ein "unvollständiger Typ" class Klasse {}; // Definition von Klasse, // Klasse ist nun ein "vollständiger Typ" int foo(int x); // Deklaration von foo, externe Bindung int foo(int x) {return x*2;} // Definition von foo, externe Bindung extern int i; // Deklaration, externe Bindung extern const int w; // Deklaration, externe Bindung int j; // Definition, externe Bindung int k = 99; // Definition, externe Bindung extern const int p = 2; // Definition, externe Bindung const int m = 2; // Definition, interne Bindung static int t; // Definition, interne Bindung static int t = 23; // Definition, interne Bindung
Ein gutes C++ Buch sollte das alles (ÜEs, Bindung, Deklaration vs Definition) erklären können.
Gruß,
SP
-
Hallo,
vielen Dank auch für deine letute Antwort. Ich denke, dass ich fast alles verstanden habe. Eine Frage bleibt mir noch.Du sagst:
int j; // Definition, externe Bindung
Ich frage mich, warum die Variable hier eine externe Bindung hat. Was ist dann der Unterschied zu:
extern int j;
?
Vielen Dank für dein (euer) Bemühen!
lg, freakC++
-
freakC++ schrieb:
Hallo,
vielen Dank auch für deine letute Antwort. Ich denke, dass ich fast alles verstanden habe. Eine Frage bleibt mir noch.Du sagst:
int j; // Definition, externe Bindung
Ich frage mich, warum die Variable hier eine externe Bindung hat. Was ist dann der Unterschied zu:
extern int j;
?
Vielen Dank für dein (euer) Bemühen!
lg, freakC++Das erste definiert j in dieser TU und stellt Speicher bereit. j ist für andere TUs sichtbar (deswegen "externe Bindung").
Das zweite deklariert j (kein Speicher wird hier bereit gestellt) und verweist auf eine andere Variable (meinetwegen auf das erste j).
Stefan.
-
freakC++ schrieb:
Du sagst:
int j; // Definition, externe Bindung
Ich frage mich, warum die Variable hier eine externe Bindung hat. Was ist dann der Unterschied zu:
extern int j;
?
Das
extern
macht aus dem Zweiten eine Deklaration.Beschwer Dich bei den Erfindern von C.
Dass
const int x = 99;
per Default interne Bindung hat ist auch eine nette C++ Eigenheit. In C ist das, soweit ich weiß, anders.
-
Hallo,
nur so eine Frage nebenbei:Ich nutzt Visual Studio 2005. Nun erstelle ich zwei Units und speicher sie im selben Verzeichnis. Nun schreibe ich folgendes:
Unit1.cpp
#include <iostream> extern a; a=4;
Unit2.cpp
//Ich arbeite eigentlich mit Borland. Ich muss jetzt hier eigentlich Unit1 einbinden, doch es kommt eine Fehlermeldung, dass diese nicht bekannt sei. //#include <Unit1.cpp> //funktionert nicht //#include "PFAD/Unit1.cpp" int main() { cout << a; }
Zwar ist mir das Konzept von extern und Co. jetzt klar, doch weiß ich noch nicht, wie ich diese anzuwenden habe. So ist a nicht
bekannt, obwohl ich ihn ja als extern gekennzeichnet habe.Könnt Ihr mal das Beispiel korrigieren oder ein anderes posten, damit ich mir vostellen kann, wie die Benutzung praktisch aussieht?
Vielen Dank
lg, freakC++
-
---- Unit1.cpp int a = 4; ---- Unit2.cpp #include <iostream> extern int a; int main() { std::cout << a << std::endl; return 0; }
Nur auf die Schnelle, also ungetestet (aber was soll da schon schiefgehen
)
Stefan.
-
ok, funzt!
Vielen Dank nochmal!
lg, freakC++
-
Du hast extern falsch verstanden. Ein Beispiel:
function.cpp
extern int a; void function(){ a=2; }
function.h
void unit1();
a.cpp
int a;
main.cpp
#include"function.h" #include<iostream> extern int a; int main(){ a=1; std::cout<<a; // 1 function(); std::cout<<a; // 2 }
edit: Da war DStefan wohl schneller
P.S.: Die Gründe die gegen globale Variablen sprechen gelten natürlich noch immer, also gewöhn dich nicht zu sehr daran. Wenn man die Variable auch noch über mehrere Übersetzungseinheiten verteilt, wird es noch schwerer Änderungen nachzuvollziehen.
-
und woher "weiß" externjetzt, auf welche Variable (auf welches a) es verweist?
Vielen Dank´
lg, freakC++
-
freakC++ schrieb:
und woher "weiß" externjetzt, auf welche Variable (auf welches a) es verweist?
Vielen Dank´
lg, freakC++Probier doch mal aus was bei mehreren Definitionen passiert...
-
@freak: Ganz am Anfang hast Du von "Sichtbarkeit" gesprochen und da hätte man eigentlich nen Fragenzeichen druntersetzen müssen. Wenn in einer ÜE etwas mit externer Bindung definiert wird, ist das dem Compiler, wenn er eine andere ÜE übersetzen will, nicht ohne weiteres bekannt. Dafür gibt es ja die Deklarationen, die man üblicherweise in Header-Dateien reinschreibt.
-
freakC++ schrieb:
und woher "weiß" externjetzt, auf welche Variable (auf welches a) es verweist?
Vielen Dank´
lg, freakC++Der Compiler weiß das gar nicht (wenn er Unit2.cpp übersetzt). Er erstellt vielmehr eine "externe Referenz", die dann der Linker auflöst. Aus diesem Grund übersetzt der Compiler TUs mit "extern"-Verweisen auch dann klaglos, wenn die referenzierte Variable nirgens definiert wird. Erst der Linker mach in einem solchen Fall Rabatz.
Der ganze Zauber daran ist ja erst die Überwindung der Grenzen von Translation Units.
Stefan.
-
freakC++ schrieb:
und woher "weiß" extern jetzt, auf welche Variable (auf welches a) es verweist?
Klammere Dich nicht an einzelne Schlüsselwörter. Die Konzepte (Bindung, Decl vs Def) dahinter sind wichtig. Da gibt es leider keine 1:1 Beziehung. Mit extern kannst Du eine externe Bindung erzwingen und sogar u.U. aus einer Definition eine Deklaration machen. Vieles hat aber auch ohne das Schlüsselwort schon eine externe Bindung.
Bzgl "welches a": Es kann nur ein a mit externer Bindung geben. Definierst Du zwei, schimpft der Linker "multiple definition of ..." (oder so ähnlich). Deklarierst Du nur und definierst nie, schimpft der Linker "undefined reference to ..." (oder so ähnlich). Der Linker ist der, der die ÜEs zusammenknotet. Er schaut sich die Kompilate der ÜEs an. In einem steht vllcht. "Ich habe ein A" (in Form einer Symboltabelle oder so). In einem anderen steht vielleicht "ich brauche ein A". Namen für Dinge mit interner Bindung interessieren den Linker weniger.
Gruß,
SP
-
Hallo,
achso...ähmm noch eine Sache zum zweiten Post von SeppJ. Du schreibst, dass es eben nicht geht, wenn ich die Unit inkludiere.
Ich habe jetzt mal mit Borland Builder 6 zwei Units erstellt und in einer eine gloable Variable erstellt. Wenn ich jetzt die eine in die
andere inkludiere, dann ist die Variable bekannt.Warum soll das dann deiner Ansicht nicht funktionieren? Habe ich dich da falsch verstanden?
Vielen Dank
lg, freakC++