C++ - Variablen: Gültigkeit - Sichtbarkeit Reiner Nitsch 8417 r.nitsch@fbi.h-da.de
Attribute von Variablen und Funktionen Attribute von Variablen sind Name (name), Typ (type), Wert (value) Attribute von Funktionen sind Name, Parameterliste (Typen und Werte), Rückgabetyp und -wert. Zusätzlich sind Variable und Funktionen charakterisiert durch die Attribute Speicherklasse (storage class) und Bindung (linkage) Speicherklasse: bestimmt den Bereich in einem Programm, in dem einem Bezeichner Speicherplatz zugewiesen ist (Gültigkeitsbereich, scope). C++ unterscheidet die Speicherklassen "Automatisch", "Statisch" und "Dynamisch". Bindung: bestimmt, ob in einem Multi-Datei-Projekt ein Bezeichner nur in einer Datei oder nach korrekter Deklaration auch in anderen Dateien des Projekts sichtbar ist. C++ unterscheidet die Bindungstypen "Intern" und "Extern". Die Schlüsselwörter auto, static und extern bestimmen Sichtbarkeitsbereich und Gültigkeitsbereich. 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 2
Gültigkeits- und Sichtbarkeitsbereich von Variablen Sichtbarkeitsbereich (SB) einer Variablen (scope): Der Bereich eines Programms, in dem auf die Variable über ihren Namen zugegriffen werden kann. Er ist abhängig von der Bindung. C++ unterscheidet die Sichtbarkeitsbereiche "Block" und "Datei" Gültigkeitsbereich (GB) einer Variablen: Der Programmbereich, in dem für die Variable ein Speicherplatz reserviert ist, der ihren aktuellen Wert hält. Er ist abhängig von der Speicherklasse (storage class) der Variablen. R1: Variable, die außerhalb von Blöcken definiert sind, bezeichnet man als externe oder globale Variablen. Sie gehören zur Speicherklasse "Statisch". Ihr Sichtbarkeitsbereich ist die Datei. Ihr Gültigkeitsbereich ist das gesamte Programm, das oft aus mehreren Dateien besteht. R2: Innerhalb eines Anweisungsblocks definierte Variablen werden automatische oder lokale Variable genannt. Sie gehören zur Speicherklasse "Automatisch". Ihr Gültigkeitsbereich beginnt nach der Deklaration und endet mit dem Block, in dem sie eingebettet sind. R3: Anweisungsblöcke können verschachtelt werden ( ). Variablennamen sind auch gültig für innerhalb des Blocks neu angelegte Blöcke (Sub-Blöcke). R4: Die Sichtbarkeit (visibility) einer Variablen (global oder lokal) wird eingeschränkt, wenn in einem Block bzw. Sub-Block eine Variable gleichen Namens definiert wird. Im Sichtbarkeitsbereich der inneren Variablen ist die äußere Variable unsichtbar (d.h. sie kann nicht mehr über ihren Namen angesprochen werden) bleibt aber immer noch gültig (d.h. ihr Speicherplatz ist noch reserviert und enthält den aktuellen Wert; siehe R3). 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 3
Gültigkeits- und Sichtbarkeitsbereich von Namen Beispiel #include <iostream> using namespace std; int a=3, b=10; int gib_a() return a; int gib_c() return c; void main () cout << a << endl; auto int a = 10; cout << a << endl; cout << ::a << endl; auto int b = 20; int c = 30; cout << b << c << ::b << endl; cout << b << endl; cout << c << endl; cout << a << endl; cout << ::a << endl; // externe (globale) Variable (R1: SB=Datei, GB=Programm) // Fehler: c nicht definiert // hier beginnt ein Anweisungsblock // Ausgabe 3; globales a (R3) // lokales a; auto ist voreingestellt und deshalb optional // Ausgabe 10; lokales a (R4) // Ausgabe 3; globales a // Gültigkeitsbereich-Auswahloperator // Subblock beginnt (R3) // lokales b sichtbar; globales b gültig, aber unsichtbar (R4) // lokales c; hier ist auto wie üblich wieder weggelassen // Ausgabe 20 30 10 // hier endet Gültigkeitsbereich von lok. b und c // Ausgabe 10; globales b wieder sichtbar // Fehler: c nicht mehr gültig (R2) // Ausgabe 10; lokales a wieder sichtbar (R4) // Ausgabe 3; globales a auto gibt explizit die Speicherklasse "Automatisch" an! // lokales a wird unsichtbar und ungültig 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 4
Lokale contra globale Variablen Das spricht für globale Variablen Sie werden vom Compiler initialisiert (mit 0) Ihr Gültigkeitsbereich ist das Programm Ihr Sichtbarkeitsbereich ist die Datei (das Programm) müssen an Funktionen nicht übergeben werden können auch bei Verdeckung sichtbar gemacht werden Das spricht gegen globale Variable Sie genießen keinen Zugriffsschutz. Jeder kann überall im Programm auf sie zugreifen. Sie machen Programme unzuverlässig. Gute Programmierer wissen (nach vielen Fehltritten) Schutz der Daten vor unberechtigtem Zugriff Deshalb: verbessert die Datenintegrität Globale Variable sollten nur für macht Programme zuverlässiger, read-only (const) Variable vereinfacht die Fehlersuche verwendet werden. macht Programme besser wartbar und pflegbar. 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 5
Erweitern des Gültigkeitsbereichs lokaler Variablen Beispiel // Datei: application.cpp #include <iostream> using namespace std; void akkumuliere(int); // Funktionsprototyp (Deklaration) int gfaktor = 2; // Gewichtsfaktor; globale Variable void main() int lv; lv=3; akkumuliere(lv); lv=5; akkumuliere(lv); // Funktion akkumuliere Version 1 (Implementation) void akkumuliere( int lv ) int summe = 0; cout << summe << " "; summe += lv * gfaktor; cout << summe << endl; // lokale Variable: GB = Block, SB = Block Ausgabe: 0 6 0 10 Funktioniert so nicht! 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 6
Erweitern des Gültigkeitsbereichs lokaler Variablen //Funktion akkumuliere Version 2 (mit statischer Variable) void akkumuliere( int lv ) static int summe = 0; cout << summe << " "; summe += lv * gfaktor; cout << summe << endl; // Initialisierung; aber statische Variable werden vom // Compiler auch automatisch mit 0 initialisiert // lokale statische Variable: GB=Programm SB=Block Ausgabe: 0 6 6 16 Schlüsselwort static weist der Variablen der Speicherklasse "Statisch" zu! 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 7
Mudularisierung von Software Ziele Modularisierung des Programmes durch Aufteilung in eigenständige Übersetzungseinheiten Effiziente Realisierung einer Programmbibliothek Prinzip Module sind Programmbausteine (Funktionen, Prozeduren, ), von denen der Anwendsprogrammierer lediglich das Interface (=Schnittstelle) kennen muss. Dieses definiert die Funktionalität und die Verwendung der Programmbausteine. Die Implementierung umfasst den tatsächlichen Code für die Funktionalität der Komponente und weitere, nur intern benötigte Funktionalität. Module bieten eine Kapselung (encapsulation) durch die Trennung von Schnittstelle und Implementierung 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 8
Prinzip der Trennung zwischen Schnittstelle und Implementierung Wie? Nützliche Funktionen werden in einer separaten Datei (*.cpp) zu Moduln zusammengefasst. Module bündeln meist Funktionen eines Anwendungsbereichs (Grafik-Modul, Mathe-Modul, ) Die Funktionsdeklarationen eines Moduls werden in Headerdateien (*.h) geschrieben. Die Headerdateien werden bei Bedarf in die Anwendungen includiert. Die compilierten Moduldatei(en) (*.obj) werden dem Linker bekannt gemacht. Beispiel folgt! 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 9
Prinzip der Trennung zwischen Schnittstelle und Implementierung Beispiel // application.cpp (Anwendung) #include <iostream> using namespace std; #include void akkumuliere(int); "modul.cpp" //Prototyp int gfaktor = 2, gv; int main() cout << gv << endl; gv=3; akkumuliere(gv); gv=5; akkumuliere(gv); int gfaktor; return 0; void akkumuliere( int lv ) static int summe = 0; cout << summe << " "; summe += lv * gfaktor; cout << summe << endl; wird includiert // modul.cpp #include <iostream> using namespace std; Programm // modul.h Enthält alle Funktionsdeklarationen #pragma once // verhindert Mehrfachinkludierung void akkumuliere(int); Schnittstelle Implementation // Implementierung void akkumuliere(int lv) static int summe; cout << gv << endl; cout << summe << " "; summe = summe + lv * gfaktor; cout << summe << endl; 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 10
Vorteile der Trennung von Interface und Implementation Bessere Wiederverwendbarkeit Kein Copy & Paste! Verbergen von Implementationsdetails (Kapselung) die der Anwender nicht zu kennen braucht, weil für ihn unwichtig die der Anwender nicht sehen soll (Schutz von "Know how", information hiding) Bessere Pflegbarkeit und Wartbarkeit des Moduls: Implementation kann geändert werden ohne Auswirkung auf rufende Programme Getrennte Übersetzung möglich Module brauchen nur einmal in Objektdateien übersetzt zu werden, da sie sich i.d.r. nicht mehr ändern Die Objektdateien der Module werden dem Linker bekannt gemacht. Der Programmierer (des rufenden Programmes) braucht sich nicht um die Details der Implementation zu kümmern. () Höhere Zuverlässigkeit der Software Fertige Module sind (hoffentlich) gründlich getestet 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 11
Erweitern des Sichtbarkeitsbereichs globaler Variablen auf andere Dateien Beispiel // application.cpp (Anwendung) #include <iostream> using namespace std; #include "modul.h" //Prototypen int gfaktor = 2, gv; int main() cout << gv << endl; gv=3; akkumuliere(gv); gv=5; akkumuliere(gv); return 0; Globale Variable gfaktor: GB=Programm, SB=application.cpp deshalb So geht's: Macht gfaktor in modul.cpp sichtbar // modul.h #pragma once void akkumuliere(int); Geht nicht: Fehler: gfaktor nicht sichtbar! // modul.cpp #include <iostream> using namespace std; int gfaktor; // Linker-Fehler: Redefinition extern int gfaktor //ok: Redeklaration //Funktion akkumuliere V2 (Implementation) void akkumuliere(int lv) static int summe; cout << gv << endl; cout << summe << " "; summe = summe + lv * gfaktor; cout << summe << endl; Programm 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 12
Einschränken des Gültigkeitsbereichs einer globalen Variablen Um Namenskonflikte zu vermeiden kann der Gültigkeitsbereichs einer globalen Variablen auch auf eine Datei begrenzt werden. Beispiel: // application.cpp static int global; int main() global = 17; // jetzt nicht mehr global weil interne Bindung, // d.h. global kann nur noch innerhalb dieser Datei verwendet werden // modul1.cpp extern int global; int global; int func1() global = 123; return global; // Versucht global aus application.cpp sichtbar zu machen // Kompilieren ok aber Linkerfehler: // Nichtaufgelöstes externes Symbol "int global" // jetzt OK! Ist in dieser Datei gültig und sichtbar. Ist in allen anderen // Dateien gültig. Ausser in application.cpp kann global auch sichtbar // gemacht werden. In application.cpp wird dieses global vom dort // intern gebundenen global verdeckt. 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 13
So, das war s erst mal! 02.04.2009 Variablen: Gültigkeit - Sichtbarkeit 14