Jason. Cała informatyka w jednym miejscu!

Kolejny rozdział poświęcony językowi C. Przyjrzymy się być może dla niektórych z Was nietypowemu zapisowi w kodzie źródłowym. Chodzi o funkcje. Zarówno w tym języku, jak i w C++, to nie wygląda tak, że wstawimy sobie funkcję gdzie chcemy i mamy z bani. Języki te są bardzo wyczulone na położenie zarówno deklaracji jak i definicji funkcji. Robi to jakąś różnicę? Jak najbardziej i to DUŻĄ. Bo przy deklaracji wstawiamy prototyp funkcji w języku C, a przy definicji "pełną" jej strukturę. Zapraszam po wyjaśnienia.

PROTOTYP FUNKCJI W JĘZYKU C. CZEMU POWINIENEŚ GO UŻYWAĆ?

Prototyp to najprościej pisząc sam nagłówek funkcji pozbawiony treści bloku. Jego zadaniem jest poinformowanie kompilatora, że w chwili wywołania pożądanej funkcji jej pełna definicja gdzieś znajduje się w kodzie i musi ją odszukać. Ponadto, umożliwia sprawdzenie poprawności wprowadzonych parametrów aktualnych (czyli wartości wprowadzanych do funkcji). W dalszej części pokażę trzy kody źródłowe w których jeden z nich będzie pokazywał czym grozi zignorowanie dodania prawidłowego nagłówka.

Prototyp funkcji w języku C zwykle umieszczany jest w przeznaczonych do tego plikach nagłówkowych, aby pomóc kompilatorowi "skleić" cały program w jeden plik wykonywalny. Czas na prezentację przykładowego kodu źródłowego z wykorzystaniem funkcji oraz jej prototypu:

#include <stdio.h>

int max(int, int);			// prototyp funkcji

int main(void)
{
	printf("Wieksza liczba z %d i %d jest %d.\n", 3, 5, max(3.0, 5.0));
	getchar();
	
	return 0;
}

int max(int n, int m)
{
	return (n > m) ? n : m;
}

Jak widzimy, mamy program z własną funkcją "max" zwracającą większą z dwóch podanych liczb. Natomiast pod dyrektywą "#include" znajduje się jeszcze prototyp funkcji "max"! Jak uprzedziłem, składa się jedynie z nagłówka czyli typu zwracanej wartości ("int"), nazwy, a także ile przyjmuje parametrów oraz jakiego typu. To jest bardzo ważne! Wiem, że w wywołaniu dorzuciłem "double" zamiast "int", ale uniknę jeszcze przez chwilę tłumaczenia i zaprezentuję kolejny kod źródłowy prezentujący "wybrakowany" prototyp funkcji w języku C obowiązujący przed standardem ANSI C w 1989 roku:

#include <stdio.h>

int max();			// prototyp funkcji przed ANSI C (1989)

int main(void)
{
	printf("Wieksza liczba z %d i %d jest %d.\n", 3, 5, max(3.0));
	getchar();
	
	return 0;
}

int max(int n, int m)
{
	return (n > m) ? n : m;
}

Zastanówcie się spokojnie, skompilujcie program i zobaczcie jakie będą kwiatki. Mamy tutaj ogromne zróżnicowanie w działaniu, a przede wszystkim szereg konsekwencji. Po pierwsze, kompilator nie uprzedzi, że wprowadzamy niewłaściwy typ do funkcji (tamten przykład stosował "obcinanie" części ułamkowej i jakoś się nam "upiekło"). Po drugie, kompilator nie znając żadnych detali na temat parametrów "zakłada", że będzie to typ "int". Mało tego, pozwala na użycie funkcji z niezgodną liczbą parametrów!!! W tym przypadku wystarczyło jedynie to, że prototyp funkcji w języku C nie dostarcza dostatecznej ilości informacji, a już tragedia wisi w powietrzu. Może Was ciekawić CO w takim razie komputer "podstawia" do drugiego parametru? Byle jaką "śmieciową" wartość, która aktualnie znajduje się w pamięci. W każdym razie, to nie jest nic dobrego...

FUNKCJA BEZ PROTOTYPU TEŻ ZADZIAŁA

Dla tych, którzy nie są przyzwyczajeni do podziału na prototyp funkcji i pełną definicję, można jeszcze napisać w następujący sposób. To jest ten sam przykład w pierwszym fragmencie:

#include <stdio.h>

int max(int n, int m)			// prototyp funkcji + pełna definicja
{
	return (n > m) ? n : m;
}

int main(void)
{
	printf("Wieksza liczba z %d i %d jest %d.\n", 3, 5, max(3.0, 5.0));
	getchar();
	
	return 0;
}

Język C weryfikuje istnienie konkretnej funkcji "schodząc" z góry na dół. Nawet jeśli zdefiniowalibyście tę funkcję, ale poniżej funkcji "main", kompilator zgłosiłby błąd z powodu nieodnalezienia żadnych "poszlak" wywoływanej funkcji. Powyższy zapis również jest poprawny, aczkolwiek nie jest on dobrą praktyką przy posługiwaniu się tym językiem. Ponadto, pozbawiacie się możliwości "podzielenia" funkcji na osobne pliki tak, aby w pliku nagłówkowym był sam prototyp funkcji w języku C (i wtedy dołączacie "includem"), a w osobnym pliku źródłowym z rozszerzeniem ".c" była pełna definicja funkcji. Tak się prawidłowo pisze, ale pouczać nie zamierzam.


To by było na tyle.

PODOBNE ARTYKUŁY