Klasa pamięci extern
Transkrypt
Klasa pamięci extern
Katedra Elektrotechniki Teoretycznej i Informatyki wykład 10 - sem.III M. Czyżak Język C Zasięg bloku Blok rozpoczyna się nawiasem otwierającym { i kończy nawiasem zamykającym. Przykład. Blok. { int x=2,n=3; x=x<<n; printf("\n x=%d",x); } Blok taki jak powyżej może być zagnieżdżany ( umieszczany wewnątrz innego bloku). Ważnym przykładem bloku jest funkcja (blok funkcji), jednak blok funkcji w językach C i C++ nie może być zagnieżdżany. Język C Zasięg bloku Zasięg bloku rozciąga się od nawiasu '{' do nawiasu '}'. Dla bloku funkcji zasięg obejmuje też parametry lokalne funkcji, w związku z tym zmienne lokalne zdefiniowane w funkcji. Przykład. Blok funkcji. int compute ( double x[], int n) { // wewnątrz tego bloku nie można definiować zmiennych o // nazwach x i n. } Język C Specyfikatory klasy pamięci ( auto, static, register, extern) Klasy pamięci dla zmiennych Specyfikatory te informują kompilator w jaki sposób przechowywać wartości poszczególnych zmiennych. Klasa pamięci określa typ pamięci, w której przechowywana jest zmienna, określa też moment utworzenia zmiennej, czas przechowywania jej wartości, jak również moment usunięcia danej zmiennej. Wyróżnia się następujące klasy pamięci: - auto - static - register - extern Język C Klasa pamięci auto ( zmienne automatyczne) Zmienna zdefiniowana wewnątrz funkcji otrzymuje domyślną klasę auto ( zwana jest zmienną automatyczną). Definicję zmiennej automatycznej można zapisać następująco auto int liczba; jednak zwykle słowo auto jest pomijane. Pamięć dla zmiennej jest alokowana (przydzielana) za każdym razem przed wejściem sterowania programu do bloku zawierającego definicję danej zmiennej i jest dealokowana (usuwana), gdy sterowanie programu opuszcza ten blok. Termin auto wywodzi się stąd, iż proces ten odbywa się automatycznie bez udziału programisty. Język C Klasa pamięci auto Zmienna typu auto jest widoczna tylko w bloku, w którym znajduje się jej definicja. Jeżeli zmienna typu auto jest jednocześnie definiowana i inicjalizowana, to jej inicjalizacja jest powtarzana za każdym razem, gdy sterowanie programu wchodzi do bloku ją zawierającego. void fun ( int n, double x) { int i,j; // zmiennymi automatycznymi są n,x,i,j } Język C Klasa pamięci static Zmienna o klasie pamięci static może być zdefiniowana wewnątrz bloku np. wewnątrz funkcji albo też na zewnątrz wszystkich bloków. Zmienne statyczne są tworzone przed rozpoczęciem wykonywania programu i istnieją przez cały czas jego wykonywania. Definicja zmiennej statycznej typu int ma postać static int liczba; Zmienne statyczne zdefiniowane wewnątrz bloku mają ten sam zasięg co inne zmienne zdefiniowane w bloku. Jednak zachowują one swą wartość po opuszczeniu bloku przez sterowanie programu. Powoduje to, na przykład, w przypadku funkcji, że wartość statycznej zmiennej lokalnej może być przechowywana pomiędzy kolejnymi wywołaniami Język C Przykład. Funkcja zliczająca i zwracająca ilość swoich wywołań. int uchwytBledu (void) { static int liczba=0; liczba++; return liczba; } Zmienna liczba jest inicjalizowana tylko jeden raz przy pierwszym wywołaniu funkcji. Przy każdym kolejnym wywołaniu, wartość zmiennej liczba jest zwiększana o 1 i przechowywana między wywołaniami funkcji, gdy sterowanie programu opuszcza blok funkcji. Język C Zmienna statyczna zdefiniowana na zewnątrz funkcji W przypadku zmiennej statycznej, która została zdefiniowana poza wszystkimi blokami ( na zewnątrz wszystkich funkcji), definicja taka ogranicza widoczność zmiennej do pliku, w którym definicja ta wystąpiła. Przykład. Zasięg zmiennej statycznej. W skład projektu wchodzą dwa pliki : plik1.c i plik2.c // plik1.c static double x; int f1 (void) { ….} // plik2.c static int x; char * f2( char *s) { …} W obu plikach występują zmienne o nazwie x, jednak są one dostępne tylko tam, gdzie występują ich definicje. Język C Klasa pamięci register Definiując zmienną typu register tworzy się zalecenie dla kompilatora, aby umieścił daną zmienną w rejestrze procesora, traktowanym jako komórka pamięci. Powodem stosowania takiego zalecenia jest czas dostępu, który jest zwykle dla rejestrów znacznie krótszy niż dla pamięci zewnętrznej. Kompilatory mogą uwzględniać to zalecenie lub nie, z drugiej strony jednak sam kompilator stara się umieszczać w rejestrach częściej używane zmienne, np. liczniki pętli. Jeżeli zmienna nie stanie się zmienną register, to będzie zmienną automatyczną. Język C Przykład. Użycie klasy pamięci register. #include <iostream> using namespace std; int main() { register int i; int sum=0; for (i=1;i<1000;i++) { sum+=i; cout<<'\n'<<"Suma="<<sum; getchar(); } return 0; } Język C Klasa pamięci extern ( zmienne zewnętrzne) Klasę pamięci extern mają tzw. zmienne zewnętrzne (globalne). Są to zmienne definiowane poza wszystkimi funkcjami w jednym z plików źródłowych składających się na program. Mogą być one dostępne w każdym miejscu programu. Po zdefiniowaniu są one dostępne w pliku źródłowym, poniżej ich definicji. Zmiennym tym w momencie definicji przypisuje się wartość 0. Jeśli chce się udostępnić zmienną w innych miejscach ( powyżej definicji zmiennej w danym pliku lub w innych plikach źródłowych) należy użyć deklaracji zmiennej z użyciem słowa extern. Język C Klasa pamięci extern Słowo extern służy do tworzenia deklaracji zmiennych zewnętrznych. extern int x;// deklaracja zmiennej zewnętrznej x void fun2(int) int fun1( int a, int b) { int c; fun2(x);// x jest zmienną zewnętrzną użytą jako argument ..... // funkcji, konieczna jest wcześniejsza deklaracja // zmiennej x przed jej użyciem w funkcji fun1 } int x; // definicja zmiennej zewnętrznej x void fun2(int a) {......... } Język C Klasa pamięci extern Słowo extern określa, że obiekt o zewnętrznej kategorii konsolidacji jest zdefiniowany w innej części programu. Słowo extern może być też zastosowane w definicji. Deklaracja zmiennej staje się definicją, gdy zmienna jest inicjowana, tzn. nadaje się jej wartość początkową, np. extern double y=5.0;// definicja zmiennej zewnętrznej y Język C Klasa pamięci extern Ważnym zastosowaniem specyfikatora extern jest sytuacja, gdy program składa z kilku plików, które mogą być osobno kompilowane i następnie konsolidowane ( łączone). W sytuacji takiej trzeba przekazać i do wszystkich plików informację o zmiennych zewnętrznych stosowanych w programie. Zmienne zewnętrzne można zdefiniować w jednym z plików, a w pozostałych plikach można umieścić deklaracje ze słowem extern; // plik pierwszy double x,y; char ch; int main( ) {/* */} void fun1(void){ // plik drugi extern double x,y; extern char ch; char * f2( char *s) { …} }; Język C Klasa pamięci extern W pliku drugim zamieszczono deklaracje poszczególnych zmiennych zewnętrznych z pliku pierwszego z modyfikatorem extern. Informuje on kompilator, że deklarowane zmienne zostały zdefiniowane w innym miejscu programu, jednak deklaracja zawiera informacje o typach i nazwach zmiennych, ale kompilator nie musi rezerwować dla nich pamięci. Deklaracje extern umieszcza się zwykle w jednym pliku nagłówkowym, który dołącza się przy użyciu dyrektywy #include do wszystkich plików źródłowych. Język C - kwalifikatory Kwalifikatory typu Każda zmienna oprócz nazwy, typu i klasy pamięci może też mieć kwalifikator typu. W języku C istnieją dwa kwalifikatory - volatile - const Kwalifikator volatile (ulotny) Kwalifikator ten wskazuje, że zmienna może być zmieniana spoza programu, w którym została zdefiniowana. Język C - kwalifikatory Przykład. Zastosowanie kwalifikatora volatile. volatile int flagaOczekiwania=1;// definicja i //inicjalizacja zmiennej void czekaj (void); int main ( ) { czekaj(); } void czekaj (void) { while ( flagaOczekiwania) ;} Język C - kwalifikatory Kwalifikator volatile Oczekiwanie będzie trwało, dopóki system operacyjny nie zmieni flagi oczekiwania, oczekiwanie to może być nieskończone. Kwalifikator volatile wskazuje , że dana zmienna może być zmieniona przez system operacyjny i kompilator nie powinien przeprowadzać optymalizacji związanych z tą zmienną ( poprzez tworzenie kopii). Język C - kwalifikatory Kwalifikator const Kwalifikator const jest kwalifikatorem służącym do definiowania specjalnych zmiennych, tzw. zmiennych ustalonych, których wartość, po jednokrotnym przypisaniu nie może ulec zmianie. Przykład. Definicja zmiennej ustalonej ( stałej). const int a=5; W powyższej instrukcji a jest zmienną ustaloną (stałą). Zmiennym ustalonym przydzielana jest pamięć w przeciwieństwie do stałych tworzonych przy użyciu #define. Słowo const zmienia interpretację zdefiniowanego obiektu. Ogranicza ono możliwość użycia do odczytu, ale zachowuje informację o typie. Język C - kwalifikatory Kwalifikator const Kwalifikator const może też służyć do ochrony przed zmianą parametrów funkcji przekazywanych przez zmienną. void druk2D( int n, int m, const double x[n][m]) { int i,j; for (i=0;i<n;i++){ for (j=0;j<m;j++) printf("%f ",x[i][j]); printf("\n"); } // x[0][0]=1; taka próba przypisania powoduje błąd kompilacji // i komunikat " assignment to read-only location", czyli próba // przypisania wartości dla lokacji tylko do odczytu } Język C - kwalifikatory Kwalifikator const Poniżej omówimy użycie kwalifikatora const dla wskaźników. Kwalifikator ten może być użyty w różny sposób, co ma określone konsekwencje odnośnie samego wskaźnika, jak i obiektów wskazywanych przez wskaźnik. Zmienna wskaźnikowa zdefiniowana bez const w sposób następujący int *wsk1; nie może przechowywać adresów stałych, natomiast może ona przechowywać adresy zmiennych i można w tym przypadku modyfikować zarówno samą zmienną wsk1 jak i wskazywaną komórkę *wsk1 . Język C - kwalifikatory Kwalifikator const Zmienna wskaźnikowa zdefiniowana z kwalifikatorem const jako const int *wsk2; może przechowywać adresy stałych jak i zmiennych. Można zmieniać wartość wskaźnika, przypisując mu np. adres zmiennej x, wsk=&x , a następnie adres zmiennej y, natomiast nie można zmieniać komórki wskazywanej przez wskaźnik, czyli *wsk2. Przy użyciu const można też utworzyć stały wskaźnik const* int wsk3; W tym przypadku można zmieniać wartość wskazywaną, czyli *wsk3, lecz nie można zmieniać samego wskaźnika wsk3. Język C - kwalifikatory Kwalifikator const Kwalifikator const może być też użyty jak niżej const int const *wsk4; wsk4 jest wtedy stałym wskaźnikiem do stałej, nie można wtedy modyfikować ani wsk4 ani też *wsk4. Możliwe jest tylko zainicjowanie wskaźnika jakimś adresem.