11.3 Wywołanie funkcji
Dalej: 11.4 Argumenty domyślne
W górę: 11. Funkcje
Wstecz: 11.2 Deklaracje i definicje funkcji
11.3 Wywołanie funkcji
Wywołanie funkcji
ma postać nazwy tej funkcji z podaną w nawiasach
okrągłych listą oddzielonych przecinkami argumentów. Oczywiście
liczba argumentów wywołania musi być dokładnie taka jak liczba
parametrów w deklaracji i definicji funkcji. Nawet jeśli funkcja jest
bezargumentowa, nawiasy musimy podać: w przeciwnym przypadku nazwa
zostanie potraktowana nie jako wywołanie, ale jak nazwa zmiennej
wskaźnikowej wskazującej funkcję (więcej o wskaźnikach funkcyjnych
powiemy w osobnym podrozdziale na ich temat ).
Rolę argumentów
mogą pełnić dowolne wyrażenia, których wartość
jest typu zgodnego z zadeklarowanym typem odpowiedniego
parametru funkcji. Nie musi być to typ identyczny z
typem parametru: wywołanie będzie prawidłowe, jeśli
wartość argumentu można niejawnie przekształcić na wartość
zadeklarowanego typu parametru
(patrz podrozdział o konwersjach standardowych ).
Jeśli przy takiej konwersji może być tracona informacja
(czyli jest to konwersja zawężająca, a nie promocja), to zazwyczaj
podczas kompilacji otrzymamy ostrzeżenia. Tym niemniej kod może
skompilować się, gdyż (w przeciwieństwie do
Javy)
takie konwersje mogą być w C/C++ legalne.
Jeśli funkcja zwraca rezultat, to ostatnią wykonywaną
instrukcją musi być zawsze instrukcja
return zwracająca
wartość typu, jaki został zadeklarowany jako typ funkcji, albo typu,
który może być niejawnie przekształcony do typu funkcji.
Jeśli funkcja jest bezrezultatowa, to
instrukcja
return może (choć nie musi) w niej występować
- jeśli występuje, to nie może zawierać żadnego wyrażenia,
którego wartość miałaby być zwrócona (za wyjątkiem wywołania
funkcji typu
void).
Dla funkcji bezrezultatowych domniemywa się instrukcję
return
tuż przed nawiasem kończącym definicję ciała tej funkcji.
Proces wywoływania możemy sobie wyobrażać tak (szczegóły mogą
zależeć od platformy i od kompilatora):
Obliczne są wartości argumentów, po czym dokonywane
są konwersje potrzebne do przekształcenia tych wartości
w wartości typu odpowiedniego parametru funkcji (co,
oczywiście, powinno być wykonalne - w przeciwnym razie
program jest błędny).
Tak uzyskane wartości kopiowane są na stos programu.
Zauważmy, że jeśli argumentem była zmienna, to na stos
kładziona jest kopia jej wartości
(po ewentualnej konwersji - wartość kładziona na stosie
musi już być dokładnie takiego typu jak
zadeklarowany typ odpowiadającego temu argumentowi parametru
funkcji). Tak więc funkcja nie uzyskuje dostępu do
zmiennej, która pełniła rolę argumentu, a tylko do kopii
jej wartości w momencie wywołania.
Sterowanie przechodzi do funkcji: kopie wartości argumentów
na stosie są utożsamiane ze zmiennymi lokalnymi
odpowiadającymi poszczególnym parametrom funkcji.
Zmienne lokalne (definiowane w funkcji) umieszczane są
również na stosie.
Wyjątek stanowią zmienne definiowane z
modyfikatorem
static.
Takie zmienne tworzone są raz: podczas pierwszego
wywołania. Przy kolejnych wywołaniach funkcja ma
dostęp do
tej samej zmiennej statycznej. Istnieje ona aż do
zakończenia
programu. Różni się od zmiennej globalnej tym, że
jej zasięgiem jest zasięg funkcji (od miejsca deklaracji
do końca funkcji).
Po zakończeniu wykonywania funkcji część stosu
ze zmiennymi lokalnymi (również tymi
odpowiadającymi parametrom funkcji), jest usuwana, tak
aby stan stosu odpowiadał temu sprzed wywołania
(zwijanie stosu). Jeśli funkcja jest rezultatowa, to
wynik jest zwracany do funkcji wywołującej
(możemy sobie wyobrażać, że również poprzez stos,
choć w praktyce stosuje się inne mechanizmy).
Rozpatrzmy przykład ilustrujący konwersje argumentów i rezultatu
funkcji:
Wyszukiwarka
Podobne podstrony:
node66 CE3G6OHPTG3WTM5STOUZXAZ7YOZVMBIG4CHFEHQnode66node66 N4LFIQ2YJ6Q6XEEUZ4XPOTSWIV66QFOGBXPDD7Anode66node66 RLQU72ZR4D6LRKFRM2BT5WANQGGJGIW56PIEDHAnode66node66więcej podobnych podstron