C/Biblioteki

Z Wikibooks, biblioteki wolnych podręczników.
< C
Skocz do: nawigacji, wyszukiwania

Czym jest biblioteka[edytuj]

Biblioteka jest to zbiór funkcji, które zostały wydzielone po to, aby dało się z nich korzystać w wielu programach. Ułatwia to programowanie - nie musimy np. sami tworzyć funkcji printf. Każda biblioteka posiada swoje pliki nagłówkowe, które zawierają deklaracje funkcji bibliotecznych oraz często zawarte są w nich komentarze, jak używać danej funkcji. W tej części podręcznika nauczymy się tworzyć nasze własne biblioteki.

Jak zbudowana jest biblioteka[edytuj]

Każda biblioteka składa się z co najmniej dwóch części (oczywiście w praktyce nie istnieje górny limit):

  • pliku nagłówkowego z deklaracjami funkcji (plik z rozszerzeniem .h)
  • pliku źródłowego, zawierającego ciała funkcji (plik z rozszerzeniem .c)

Budowa pliku nagłówkowego[edytuj]

Oto najprostszy możliwy plik nagłówkowy:

 #ifndef PLIK_H
 #define PLIK_H
 /* tutaj są wpisane deklaracje funkcji */
 #endif

Zapewne zapytasz się na co komu instrukcje #ifndef, #define oraz #endif. Otóż często się zdarza, że w programie korzystamy z plików nagłówkowych, które dołączają się wzajemnie. Oznaczałoby to, że w kodzie programu kilka razy pojawiła by się zawartość tego samego pliku nagłówkowego. Instrukcja #ifndef i #define temu zapobiega. Dzięki temu kompilator nie musi kilkakrotnie kompilować tego samego kodu.


W plikach nagłówkowych często umieszcza się też definicje typów, z których korzysta biblioteka albo np. makr.

Budowa najprostszej biblioteki[edytuj]

Załóżmy, że nasza biblioteka będzie zawierała jedną funkcję, która wypisuje na ekran tekst "pl.Wikibooks". Utwórzmy zatem nasz plik nagłówkowy:

 #ifndef WIKI_H
 #define WIKI_H
 #include <stdio.h>
 void wiki (void) {printf("pl.Wikibooks\n");}
 #endif

Należy pamiętać, o podaniu void w liście argumentów funkcji nie przyjmujących argumentów. O ile przy definicji funkcji nie trzeba tego robić (jak to często czyniliśmy w przypadku funkcji main) o tyle w prototypie brak słówka void oznacza, że w prototypie nie ma informacji na temat tego jakie argumenty funkcja przyjmuje.

Plik nagłówkowy zapisujemy jako "wiki.h".

Ważne jest dołączenie na początku pliku nagłówkowego. Dlaczego? Plik nagłówkowy zawiera deklaracje naszych funkcji - jeśli popełniliśmy błąd i deklaracja nie zgadza się z definicją, kompilator od razu nas o tym powiadomi. Oprócz tego plik nagłówkowy może zawierać definicje istotnych typów lub makr. Napiszmy nasz program:

 #include "wiki.h"
 
 int main ()
 {
   wiki();
   return 0;
 }

Zapiszmy program jako "main.c" Teraz musimy odpowiednio skompilować nasz program:

gcc main.c -o main

Uruchamiamy nasz program:

./main
pl.Wikibooks

Jak widać nasza pierwsza biblioteka działa.


Zmiana dostępu do funkcji i zmiennych (static i extern)[edytuj]

Język C, w przeciwieństwie do swego młodszego krewnego - C++ nie posiada praktycznie żadnych mechanizmów ochrony kodu biblioteki przed modyfikacjami. C++ ma w swoim asortymencie m.in. sterowanie uprawnieniami różnych elementów klasy. Jednak programista, piszący program w C nie jest tak do końca bezradny. Autorzy C dali mu do ręki dwa narzędzia: extern oraz static. Pierwsze z tych słów kluczowych informuje kompilator, że dana funkcja lub zmienna istnieje, ale w innym miejscu, i zostanie dołączona do kodu programu w czasie łączenia go z biblioteką.

extern przydaje się, gdy zmienna lub funkcja jest zadeklarowana w bibliotece, ale nie jest udostępniona na zewnątrz (nie pojawia się w pliku nagłówkowym). Przykładowo:

 /* biblioteka.h */
#ifndef BIBLIOTEKA_H
#define BIBLIOTEKA_H
 extern char zmienna_dzielona[];
#endif
 /* biblioteka.c */
 #include "biblioteka.h"
 
 char zmienna_dzielona[] = "Zawartosc";
 
 /* main.c */
 #include <stdio.h>
 #include "biblioteka.h"
 
 int main() 
 {
   printf("%s\n", zmienna_dzielona);
   return 0;
 }

Gdybyśmy tu nie zastosowali extern, kompilator (nie linker) zaprotestowałby, że nie zna zmiennej zmienna_dzielona. Próba dopisania deklaracji char zmienna_dzielona[]; stworzyłaby nową zmienną i utracilibyśmy dostęp do interesującej nas zawartości.

Odwrotne działanie ma słowo kluczowe static użyte w tym kontekście (użyte wewnątrz bloku tworzy zmienną statyczną, więcej informacji w rozdziale Zmienne). Może ono odnosić się zarówno do zmiennych jak i do funkcji globalnych. Powoduje, że dana zmienna lub funkcja jest niedostępna na zewnątrz biblioteki[1]. Możemy dzięki temu ukryć np. funkcje, które używane są przez samą bibliotekę, by nie dało się ich wykorzystać przez extern.

Przypisy

  1. Tak naprawdę całe "ukrycie" funkcji polega na zmianie niektórych danych w pliku z kodem binarnym danej biblioteki (pliku .o), przez co linker powoduje wygenerowanie komunikatu o błędzie w czasie łączenia biblioteki z programem.