Specyfikatory klasy magazynowania dla deklaracji na poziomie zewnętrznym (C)
Zmienne zewnętrzne są zmiennymi w zakresie pliku.Są zdefiniowane poza jakąkolwiek funkcją i są potencjalnie dostępne dla wielu funkcji.Funkcje mogą być definiowane tylko na poziomie zewnętrznym i dlatego nie mogą być zagnieżdżane.Domyślnie wszystkie odwołania do zmiennych zewnętrznych i funkcji o tej samej nazwie są odwołaniami do tego samego obiektu, co oznacza, że mają one "powiązanie zewnętrzne." (Można użyć słowa kluczowego static, aby to zmienić.Zobacz w dalszej części tej sekcji, aby uzyskać więcej szczegółów static.)
Deklaracje zmiennych na poziomie zewnętrznym są definicjami zmiennych ("deklaracje definiujące") lub odwołaniami do zmiennych określonych gdzie indziej ("deklaracje odwołaniowe").
Zewnętrzna deklaracja zmiennej, która także inicjuje zmienną (jawnie lub niejawnie) jest deklaracja definiującą zmienną.Definicja na poziomie zewnętrznym może przybierać różne formy:
Zmienna deklarowana za pomocą specyfikatora klasy magazynu static.Można jawnie zainicjować zmienną static stałym wyrażeniem, zgodnie z opisem w Inicjalizacja.Jeżeli pominięto inicjator, zmienna jest inicjowana domyślnie na wartość 0.Na przykład następujące dwie instrukcje są rozważane jako definicje zmiennej k.
static int k = 16; static int k;
Zmienna jawnie zainicjowana na poziomie zewnętrznym.Na przykład int j = 3; jest definicją zmiennej j.
W deklaracjach zmiennych na poziomie zewnętrznym (czyli poza wszystkimi funkcjami) można użyć specyfikatora klasy magazynu static lub extern lub całkowicie pominąć specyfikator klasy magazynu.Nie można użyć terminali specyfikatora klasy magazynuauto i register na poziomie zewnętrznym.
Gdy zmienna jest zdefiniowana na poziomie zewnętrznym, jest widoczna w pozostałej części jednostki tłumaczenia.Zmienna nie jest widoczna przed jej deklaracją, w tym samym pliku źródłowym.Ponadto nie jest widoczna w innych plikach źródłowych programu, chyba że deklaracja odwołaniowa uwidacznia ją, jak opisano poniżej.
Zasady odnoszące się do static obejmują:
Zmienne zadeklarowane poza wszystkimi blokami bez słowa kluczowego static zawsze zachowują swoje wartości w całym programie.Aby ograniczyć ich dostęp do określonej jednostki tłumaczenia, należy użyć słowa kluczowego static.To daje im "powiązanie wewnętrzne." Aby stworzyć je globalnie dla całego programu, należy pominąć jawną klasę magazynu lub użyć słowa kluczowego extern (patrz zasady na następnej liście).To daje im "powiązanie zewnętrzne." Połączenia wewnętrzne i zewnętrzne są również omówione w Połączenia.
Można zdefiniować zmienną na poziomie zewnętrznym tylko raz w programie.Można zdefiniować inną zmienną o tej samej nazwie i specyfikatorem klasy magazynu static w innej jednostce translacji.Ponieważ każda definicja static jest widoczna tylko w ramach własnej jednostki tłumaczenia, konflikt nie wystąpi.Zapewnia to przydatny sposób ukrywania nazw identyfikatorów, które muszą być udostępnione wśród funkcji pojedynczej jednostki tłumaczenia, ale nie są widoczne dla innych jednostek tłumaczenia.
Specyfikator klasy magazynu static można także zastosować do funkcji.Jeśli deklarowana jest funkcja static, jej nazwa jest niewidoczna poza plikiem, w której jest zadeklarowana.
Regułami korzystania z extern są:
Specyfikator klasy magazynu extern deklaruje odwołanie do zmiennej zdefiniowanej w innym miejscu.Można użyć deklaracji extern, aby uwidocznić definicję w innym pliku źródłowym lub uwidocznić zmienną przed jej definicją w tym samym pliku źródłowym.Po zadeklarowaniu odwołania do zmiennej na poziomie zewnętrznym, zmienna jest widoczna w pozostałej części jednostki tłumaczenia, w której występuje zadeklarowane odwołanie.
Aby odwołanie extern było prawidłowe, zmienna do której się odnosi, musi być zdefiniowana raz i tylko raz, na poziomie zewnętrznym.Ta definicja (bez klasy magazynu extern) może być w dowolnej jednostce tłumaczenia, tworzącej program.
Przykład
Poniższy przykład ilustruje deklaracje zewnętrzne:
/******************************************************************
SOURCE FILE ONE
*******************************************************************/
#include <stdio.h>
extern int i; // Reference to i, defined below
void next( void ); // Function prototype
int main()
{
i++;
printf_s( "%d\n", i ); // i equals 4
next();
}
int i = 3; // Definition of i
void next( void )
{
i++;
printf_s( "%d\n", i ); // i equals 5
other();
}
/******************************************************************
SOURCE FILE TWO
*******************************************************************/
#include <stdio.h>
extern int i; // Reference to i in
// first source file
void other( void )
{
i++;
printf_s( "%d\n", i ); // i equals 6
}
Dwa pliki źródłowe w tym przykładzie zawierają łącznie trzy zewnętrzne deklaracje i.Tylko jedna deklaracja jest "deklaracją definiującą". Deklaracja,
int i = 3;
definiuje zmienną globalną i oraz inicjuje ją początkową wartością 3.Deklaracja "odwołaniowa" i w górnej części pierwszego pliku źródłowego używająca extern sprawia, że zmienna globalna jest widoczna przed jej deklaracją definiującą w pliku.Deklaracja odwołaniowa i w drugim pliku źródłowym również sprawia, że zmienna jest widoczna w tym pliku źródłowym.Jeśli wystąpienie definiujące zmiennej nie jest dostarczone w jednostce tłumaczenia, kompilator zakłada deklarację odwołaniową
extern int x;
oraz odwołanie definiujące
int x = 0;
pojawia się w innej jednostce tłumaczenia programu.
Wszystkie trzy funkcje main, next i other, wykonują to samo zadanie: zwiększają i i wypisują ją.Drukowane są wartości 4, 5 i 6.
Jeśli zmienna i nie była zainicjowana, to zostanie automatycznie ustawiona na 0.W tym przypadku byłyby wypisane wartości 1, 2 i 3.Zobacz Inicjalizacja, aby uzyskać informacje na temat inicjalizacji zmiennej.