DODATEK A PRZEWODNIK JĘZYKA C________
jednostka-tłumaczen ia:
deklaracja-zewnętrzna
jednostka-tłumaczenia deklaracja-zewnętrzna
deklaracja-zewnętrzna: defin icja-funkcji deklaracja
Zasięg deklaracji zewnętrznych rozciąga się do końca zawierającej je jednostki tłumaczenia, podobnie jak zasięg deklaracji zawartych w bloku rozciąga się do końca tego bloku. Składnia deklaracji zewnętrznej jest taka sama, jak składnia wszystkich innych deklaracji, jednakże tylko na tym poziomie można podać treść funkcji.
Definicja funkcji ma postać defin icja-funkcji:
specyfikatory-deklaracji0fK deklarator lista-deklaracji()lK instrukcja-złożona
Dozwolonymi specyfikatorami klasy pamięci w specyfikatorach deklaracji są tylko extem i static; różnice między nimi opisano w p. Al 1.2.
Funkcja może zwracać wartość typu arytmetycznego, strukturę, unię, wskaźnik lub void; natomiast nie może zwrócić funkcji ani tablicy. Deklarator w deklaracji funkcji musi jawnie wskazywać, że deklarowany identyfikator ma typ funkcyjny, tzn. musi zawierać jedną z poniższych konstrukcji (patrz p. A8.6.3):
bezpośredni-deklarator (lista-typów-parametrów ) bezpośredni-deklarator (lista-identyfikatorówofK.)
gdzie bezpośredni-deklarator jest identyfikatorem, ewentualnie ujętym w nawiasy. W szczególności nie można zbudować typu funkcyjnego za pomocą typedef.
Pierwsza postać deklaratora definiuje funkcję w nowym stylu; jej parametry wraz z typami są deklarowane na liście typów parametrów; listę deklaracji, następującą po deklaratorze funkcji, należy pominąć. Jeżeli lista typów parametrów nie składa się wyłącznie ze słowa void oznaczającego funkcję bezparametrową, to każdy z deklara-torów na liście typów parametrów musi zawierać identyfikator. Jeśli lista parametrów kończy się wielokropkiem to funkcja może być wywołana z liczbą argumen-
A10 DEKLARACJE ZEWNĘTRZNE ____1 Powerej bV I
tów większą niż liczba parametrów; w odwołaniach do nad 1 iczbowych ^
należy stosować mechanizm makra va_arg, zdefiniowany w standardowym nagłówku <stdarg.h> i opisany w dodatku B. Funkcje ze zmienną listą argumentów muszą mieć co najmniej jeden nazwany parametr.
Druga postać deklaratora definiuje funkcję w starym stylu; na liście identyfikatorów występują nazwy parametrów, podczas gdy lista deklaracji określa ich typy. Jeśli dla parametru nic podano deklaracji, to przyjmuje się typ int. Lista deklaracji może zawierać deklaracje tylko tych parametrów, które umieszczono na liście parametrów; inicjowanie jest zakazane, a jedynym możliwym specyfikatorem klasy pamięci jest register.
W obu postaciach definicji funkcji przyjmuje się, że parametry są deklarowane na samym początku instrukcji złożonej tworzącej treść funkcji - nie można więc tam ponownie deklarować tych samych identyfikatorów (chociaż można je, jak i inne identyfikatory, deklarować w blokach wewnętrznych). Jeśli parametr jest zadeklarowany jako „tablica elementów typu”, to tę deklarację zamienia się na „wskaźnik do typiT\ podobnie, jeśli parametr jest zadeklarowany jako „funkcja zwracająca typ", to tę deklarację zamienia się na „wskaźnik do funkcji zwracającej typ". Przy wywołaniu funkcji argumenty są przekształcane w miarę potrzeby i wstawiane do parametrów; patrz p. A7.3.2.
Nowy styl definicji funkcji pojawił się wraz z ANSI C. Nastąpiła również drobna zmiana w promocji typów: w pierwszym wydaniu mówiło się, że parametry zadeklarowane jako float będą rozciągane do typu double. Różnica ta staje się widoczna, gdy wewnątrz funkcji jest generowany wskaźnik do takiego parametru.
Oto pełny przykład definicji funkcji w nowym stylu:
int max(int a, int b, int c)
int m;
m = (a > b) ? a : b; return (m > c) ? m : c;
Tutaj int jest specyfikatorem deklaracji; max(int a, int b, int c) jest deklaratorem funkcji, a { ... } jest blokiem stanowiącym treść funkcji. Odpowiednia definicja funkcji w starym stylu wyglądałaby następująco:
301