Przykład podziału na pliki
Podział na pliki
Wyobraźmy sobie sytuację, że mamy duuuży program… duuużo większy niż ten poniżej…
Tak więc wyobraźmy sobie, że program poniżej jest duuużo większy :]
#include <stdio.h> typedef struct { char nazwisko[20]; int wiek; } Osoba; void wczytaj(Osoba* s) { printf("Podaj nazwisko: "); scanf("%s", s->nazwisko); printf("Podaj wiek: "); scanf("%d", &s->wiek); } void wyswietl(const Osoba* s) { printf("%s ma lat: %d\n", s->nazwisko, s->wiek); } int main(void) { Osoba osoba; int klawisz; do { printf("\n Menu:\n"); printf("-> 1 - wczytaj dane\n"); printf("-> 2 - wyswietl dane\n"); printf("-> 3 - zakoncz program\n"); printf("Wybieram -> "); scanf("%d", &klawisz); switch(klawisz) { case 1: wczytaj(&osoba); break; case 2: wyswietl(&osoba); break; } } while(klawisz != 3); return 0; }
W takim przypadku zachodzi potrzeba podzielenia go na pliki. Jak to zrobić? Na przykład tak:
- plik osoba.h
#ifndef _OSOBA_H #define _OSOBA_H typedef struct { char nazwisko[20]; int wiek; } Osoba; void wczytaj(Osoba* s); void wyswietl(const Osoba* s); #endif
- plik osoba.c
#include <stdio.h> #include "osoba.h" void wczytaj(Osoba* s) { printf("Podaj nazwisko: "); scanf("%s", s->nazwisko); printf("Podaj wiek: "); scanf("%d", &s->wiek); } void wyswietl(const Osoba* s) { printf("%s ma lat: %d\n", s->nazwisko, s->wiek); }
- plik main.c
#include <stdio.h> #include "osoba.h" int main(void) { Osoba osoba; int klawisz; do { printf("\n Menu:\n"); printf("-> 1 - wczytaj dane\n"); printf("-> 2 - wyswietl dane\n"); printf("-> 3 - zakoncz program\n"); printf("Wybieram -> "); scanf("%d", &klawisz); switch(klawisz) { case 1: wczytaj(&osoba); break; case 2: wyswietl(&osoba); break; } } while(klawisz != 3); return 0; }
Kompilacja programu podzielonego na pliki
Powyższy program wielomodułowy możemy skompilować:
gcc main.c osoba.c
Jednak w ogólnym przypadku lepsza jest kompilacja równoległa, a potem linkowanie modułów:
gcc osoba.c -o osoba.o gcc main.c -o main.o gcc main.o osoba.o -o program
Więcej informacji o procesie kompilacji można znaleźć na stronie laboratorium GCC - proces kompilacji.
Zamiast pisać pojedynczo poszczególne komendy, warto zapoznać się z narzędziem Make, które wspomaga proces budowania wielomodułowego kodu. Make obsługuje złożone zależności pomiędzy plikami źródłowymi, w szczególności gdy zmiany w jednych pociągają rekurencyjnie zmiany w kolejnych.
Make działa zawsze w obrębie katalogu bieżącego i potrzebuje pliku konfiguracyjnego Makefile. Plik ten składa się z szeregu reguł postaci (–> oznacza tabulator!):
cel: prerekwizyty -->-->polecenia -->-->polecenia
Legenda:
- cel - nazwa pliku,
- prerekwizyty - lista nazw plików,
- polecenia - polecenia do wykonania
Jak to działa?
make
uruchamia tylko pierwszą regułę.- Reguła jest odpalana, gdy data modyfikacji choć jednego prerekwizytu jest późniejsza niż data modyfikacji celu.
- Dla każdego prerekwizytu, którego data modyfikacji jest późniejsza niż data modyfikacji celu, rekurencyjnie uruchamiana jest reguła która go definiuje (o ile istnieje).
- Po spełnieniu prerekwizytów uruchamiane są polecenia.
Można również wymusić uruchomienie dowolnego celu z pliku Makefile wywołując: make cel
.
Niektóre z reguł nie muszą być związane z samą kompilacją, ale czynnościami pomocniczymi np.
clean: -->-->rm -f *.o program
usuwa pliki powstałe w trakcie kompilacji wraz ze skompilowaną wersją programu.
Przykładowy plik Makefile dla naszego programu może wyglądać następująco:
program: osoba.o osoba.h gcc -Wall -ansi -pedantic -lm main.c osoba.o -o program @echo program: zbudowane! osoba.o: osoba.c gcc -c -Wall -ansi -pedantic osoba.c clean: rm -f *.o program
Teraz, aby skompilować program wystarczy wydać polecenie make
.
Make posiada również zaawansowane mechanizmy, jak np. wzorce reguł. Więcej o tym i innych rzeczach związanych z programem GNU Make można się dowiedzieć na stronie laboratorium dot. GNU Make.
Program z poprzednich zajęć (słownik krzyżówkowy) rozdziel na kilka plików. Stwórz bibliotekę wyszukującą w słowniku (więcej informacji: jak stworzyć bibliotekę).