Spis treści
1 Znaczenie dla zmiennych i stałych
2 Znaczenie dla funkcji
3 Znaczenie dla fragmentów kodu
4 Konsolidacja języka C/C++ z innymi językami
Extern
extern<justify>Jedno ze słów kluczowych oraz specyfikatorów (kwalifikatorów, modyfikatorów) klas pamięci dla deklarowanych obiektów. Oznacza, że deklaracja nie jest deklaracją w sensie fizycznym, a jedynie odwołaniem do deklaracji znajdującej się w innej jednostce kompilacji (module, pliku, bibliotece - przyp. autora). Jednym słowem, jest to sposób na poinformowanie kompilatora, by nie szukał danej zmiennej globalnej w aktualnym pliku. Jednak na tym nie koniec możliwości tego modyfikatora.</justify>
Specyfikatory extern i static wzajemnie się wykluczają, dlatego nie zaleca się tworzenia deklaracji zawierających obydwa te słowa jednocześnie. Ponadto zabroniona jest inicjalizacja zmiennej zadeklarowanej z użyciem modyfikatora extern!
Znaczenie dla zmiennych i stałych
<justify> Jak już zostało wspomniane, jeżeli extern poprzedza deklarację nie zainicjalizowanej zmiennej (globalnej lub lokalnej) albo stałej, oznacza to wówczas, że deklarowany obiekt nie zawiera się w danym pliku, a w innej jednostce kompilacji (może to być inny moduł, nagłówek, biblioteka statyczna lub dynamiczna itp.):</justify>/* ==== plik1.c ===== */ #include <stdio.h> #include <stdlib.h> int liczba; /* deklaracja zmiennej globalnej */ /* ... */ liczba = 13; /* ... */
/* ==== plik2.c ===== */ #include <stdio.h> #include <stdlib.h> #include "plik1.h" extern int liczba; /* deklaracja zmiennej globalnej, znajdującej się w pliku 'plik1.c' */ int main (int argc, char** argv) { printf("liczba=%d\n", liczba); /* → wypisze na wyjściu: liczba=13 */ return 0; }
<justify> Jeżeli specyfikator ten poprzedza deklarację stałej zainicjalizowanej, oznacza to, że taka stała posiada łączność zewnętrzną (więc z kolei extern przed stałą niezainicjalizowaną importuje taką stałą). W odróżnieniu od zmiennych, które można powstrzymać przed eksportowaniem symbolu przez specyfikator static, stałe globalne wymagają extern, żeby eksportować symbol na zewnątrz.</justify>
Obiekty stają się globalne dla całego programu, gdy ominie się specyfikację klasy pamięci lub zastosuje słowo kluczowe extern, co nadaje im łączność zewnętrzną.
Znaczenie dla funkcji
<justify> Wewnątrz funkcji deklaracje ze specyfikatorem extern również wskazują, że pamięć dla deklarowanych obiektów będzie zarezerwowana gdzie indziej. Jeżeli deklaracja obiektu wewnątrz bloku (pętli, funkcji itp. - przyp. autora) nie zawiera specyfikatora extern, wówczas obiekt ten nie ma łączności i jest unikalny w funkcji. W przeciwnym wypadku, gdy w zasięgu otaczającym dany blok obowiązuje zewnętrzna deklaracja tego samego obiektu, wówczas ma on taka samą łączność, jak w deklaracji zewnętrznej i odnosi się do tego samego obiektu:</justify>/* ===== external.c ===== */ #include <stdio.h> #include <stdlib.h> extern int liczba; /* zmienna zadeklarowana w innym module */ int main (int argc, char** argv) { int liczba; { extern int liczba; /* deklaracja odwołuje się do zmiennej liczba, zadeklarowanej w obrębie najbliższego bloku */ } return 0; }
<justify> Nierzadko można natrafić na deklarację prototypu funkcji, której typ wartości zwracanej poprzedzony jest specyfikatorem extern. Oznaczać to może chociażby deklarację funkcji, której ciało (oraz pierwotna deklaracja) znajduje się w innym module. Opcjonalnie można stosować ten specyfikator przed deklaracjami prototypu funkcji w tym samym module, zwłaszcza, gdy ciało danej funkcji umieszczona zostało poniżej funkcji głównej:</justify>
#include <stdio.h> #include <stdlib.h> extern int kwadrat (int liczba); int main (int argc, char** argv) { printf("Kwadrat liczby 8 wynosi %d\n", kwadrat(8)); return 0; } int kwadrat (int liczba) { return liczba*liczba; }
<justify> Jak jednak zostało wspominane, nie jest to zabieg konieczny, a co za tym idzie, większość kompilatorów ignoruje ten specyfikator przed nazwą funkcji (każda deklaracja funkcji posiada ten kwalifikator domyślnie). Często jest to jednak wymóg w przypadkach, gdy w skład projektu wchodzą m.in. pliki asemblerowskie. Dzięki deklaracji z użyciem extern można się odwoływać do funkcji napisanych w assemblerze, a nigdzie wcześniej niezadeklarowanych (trochę więcej na ten temat w tej części artykułu).</justify>
Znaczenie dla fragmentów kodu
<justify> Znaczenie zgoła inne niż dotychczas słowo kluczowe extern ma w języku C++ dla objętych specjalnym blokiem fragmentów kodu. Dzięki wspomnianemu blokowi możliwe jest jawne określenie języka nadającego reguły kompilacji dla danego bloku:</justify>extern "C" { typedef struct stDrzewo { int data; struct stDrzewo *next; } drzewoBST; }
<justify> Fragment kodu z powyższego przykładu zostanie skompilowany zgodnie z regułami kompilacji języka ANSI C.</justify>
Język C może być bardzo łatwo konsolidowany (łączony) z wieloma innymi językami, które kompilowane są bezpośrednio do kodu maszynowego (m.in.: Assembler, Fortran oraz C++). Ponadto dzięki specjalnym bibliotekom można go łączyć z językami bardzo wysokiego poziomu (takimi jak np. Python czy też Ruby)
<justify> Dzięki tej metodzie można równie dobrze ograniczyć niektóre, dość irytujące aspekty języka, które pierwotnie nie występowały w czystym C, a pojawiły się w C++. Przykładem może tu być różnica działania typu wyliczeniowego enum dla obu języków. Ponadto jest to doskonały sposób na dołączenie biblioteki, czy też modułu napisanego w całości w czystym C, bez obawy o niekompatybilność:</justify>
extern "C" { #include "tablice_c.h"; }
<justify>a także na określenie języka nadającego reguły kompilacji dla danej funkcji:</justify>
extern "C" void kwadrat (void);
Funkcja poprzedzona extern "C" nie może podlegać przeciążaniu (co nie oznacza, że nie może być wiele funkcji o tej samej nazwie; ograniczenie to tyczy się zastosowania specyfikatora extern "C" jedynie dla jednej deklaracji funkcji o danej nazwie).
<justify>Na podobnej zasadzie umieszcza się w kodzie wstawki asemblerowskie:</justify>
#include <cstdio> int main(void) { asm { mov eax, 1 } return 0; }
Konsolidacja języka C/C++ z innymi językami
<justify> Jak już zostało wcześniej wspominane, kod źródłowy języka C można bez problemu konsolidować ze źródłami innych języków, pod warunkiem, że ich kompilacja następuje bezpośrednio do kodu maszynowego. Rozważmy program składający się z dwóch modułów - jeden jako plik źródłowy poleceń asemblerowskich, drugi jako zwykły kod języka C.</justify>plik_asm.S
.text .globl _funkcja ; deklaracja funkcji o nazwie 'funkcja' _funkcja: pushl %ebp movl %esp, %ebp movl $4, %eax ; 4 to funkcja systemowa "write" movl $1, %ebx ; 1 to stdout movl $tekst, %ecx ; adres naszego napisu movl $len, %edx ; długość napisu w bajtach int $0x80 ; wywołanie przerwania systemowego popl %ebp ret .data tekst: .string "Witaj \305\233wiecie!\n" len = . - tekst
plik_c.c
extern void funkcja (void); /* musimy użyć słowa extern */
int main ()
{
funkcja ();
return 0;
}
<justify>po skompilowaniu (np. przy użyciu uniksowego GCC):</justify>
as plik_asm.S -o plik_asm.o
gcc plik_c.c -c -o plik_c.o
gcc plik_c.o plik_asm.o -o program
<justify>powinniśmy otrzymać program wypisujący na ekranie frazę:</justify>
<font>Witaj świecie!</font>
<justify> Należy zauważyć, że w powyższym przykładzie językiem wiodącym jest C. Ponadto w kodzie użyta jest funkcja, której ciało znajduje się w innym module (mało tego - dodatkowo w innym języku), a nigdzie nie występuje deklaracja jej prototypu, dlatego konieczne jest tutaj użycie słowa kluczowego extern przed deklaracją tej funkcji w danym module.</justify>
na podstawie wikibooks.org
Zobacz też:
Kategoria: C/C++