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.