Zakres widoczności identyfikatorów to fundamentalna koncepcja określająca, gdzie w programie dostępne są zmienne, funkcje lub inne byty. Kwestia zarządzania widocznością ma bogatą historię - od pierwszych implementacji C, niewłaściwe użycie zakresów widoczności prowadziło do trudnych do odtworzenia błędów związanych z nadpisywaniem, nieoczekiwanym zachowaniem i błędami linkowania.
C początkowo zaprojektowano z myślą o małych projektach, gdzie cały program znajdował się w jednym pliku. Z ewolucją języka pojawiła się potrzeba wyraźnego oddzielenia zmiennych/funkcji dla różnych części programu, co doprowadziło do sformalizowania zakresów widoczności: lokalnym, plikowym i globalnym.
Bez prawidłowo zorganizowanego zakresu widoczności można przypadkowo zmienić wartości zmiennych używanych w różnych częściach programu, uzyskać konflikty nazw lub stracić kontrolę nad strukturą programu. Błędy z "cieniowanymi" zmiennymi i zakrywaniem globalnych definicji lokalnymi - to częsta przyczyna błędów.
W C zakres widoczności może być:
{ ... } (na przykład w funkcji lub pętli). Poza blokiem zmienna "zapomina się".Przykład kodu:
#include <stdio.h> int global = 10; // globalny zakres widoczności void foo() { int block_var = 5; // lokalny zakres widoczności static int static_file_var = 0; // plikowy, gdy static poza funkcjami printf("%d ", block_var); } int main() { printf("%d ", global); // widoczna globalna foo(); // printf("%d ", block_var); // błąd: block_var nie jest widoczna return 0; }
Kluczowe cechy:
1. Jeśli globalna zmienna i parametr funkcji mają tę samą nazwę, co będzie używane wewnątrz funkcji?
Funkcja "cieniue" globalną zmienną parametrem, dlatego wewnątrz funkcji używane jest wartość parametru. Globalna zmienna jest dostępna tylko pod inną nazwą (jeśli nie jest zakryta).
2. static wewnątrz funkcji a static poza funkcją: czy zakres widoczności jest taki sam?
Nie! static wewnątrz funkcji (static local) - zmienna zachowuje wartość między wywołaniami, ale jest widoczna tylko w tej funkcji. static poza funkcjami - ogranicza widoczność zmiennej/funkcji do bieżącego pliku.
Przykład kodu:
static int a = 0; // zakres plikowy void foo() { static int b = 0; // zakres lokalny }
3. Czy można używać nazwy lokalnej zmiennej, która pokrywa się z globalną?
Tak, ale to spowoduje "cieniowanie" globalnej w obrębie bieżącego bloku. To prowadzi do błędów z powodu nieprawidłowego dostępu do niewłaściwej wartości.
Przykład kodu:
int var = 10; void f() { int var = 20; printf("%d", var); // wyświetla 20, globalna niewidoczna }
Projekt podzielony na 2 pliki. Takie same globalne zmienne zadeklarowane w obu plikach bez static/extern. Linker zgłasza błąd lub program działa z nieoczekiwanymi wartościami.
Zalety:
Wady:
Wyraźnie używane static i extern, zmienne przeniesione do osobnego nagłówka, opisane zasady nazewnictwa.
Zalety:
Wady: