Interpretowanie deklaratorów bardziej złożonych
Można ująć dowolny deklarator w nawiasy, aby określić konkretną interpretację "złożonego deklaratora". Deklarator złożony jest identyfikatorem kwalifikowanym przez więcej niż jedną tablicę, wskaźnik lub modyfikator funkcji. Do pojedynczego identyfikatora można zastosować różne kombinacje tablic, wskaźników i modyfikatorów funkcji. Ogólnie może typedef
służyć do uproszczenia deklaracji. Zobacz Deklaracje typedef.
W interpretowaniu deklaratorów złożonych nawiasy i nawiasy (czyli modyfikatory po prawej stronie identyfikatora) mają pierwszeństwo przed gwiazdkami (czyli modyfikatorami po lewej stronie identyfikatora). Nawiasy i nawiasy mają ten sam pierwszeństwo i kojarzą się od lewej do prawej. Po pełnym zinterpretaniu deklaratora specyfikator typu jest stosowany jako ostatni krok. Za pomocą nawiasów można zastąpić domyślną kolejność skojarzeń i wymusić konkretną interpretację. Nigdy nie używaj nawiasów, jednak wokół samej nazwy identyfikatora. Może to być błędnie interpretowane jako lista parametrów.
Prostym sposobem interpretowania złożonych deklaratorów jest odczytanie ich "z wnętrza", wykonując następujące cztery kroki:
Zacznij od identyfikatora i spójrz bezpośrednio po prawej stronie nawiasów lub nawiasów (jeśli istnieją).
Zinterpretuj te nawiasy lub nawiasy, a następnie poszukaj po lewej stronie gwiazdki.
Jeśli napotkasz prawy nawias na dowolnym etapie, wróć i zastosuj reguły 1 i 2 do wszystkich elementów w nawiasach.
Zastosuj specyfikator typu.
char *( *(*var)() )[10]; ^ ^ ^ ^ ^ ^ ^ 7 6 4 2 1 3 5
W tym przykładzie kroki są numerowane w kolejności i można je interpretować w następujący sposób:
Identyfikator
var
jest zadeklarowany jakowskaźnik do
funkcja zwracająca
wskaźnik do
tablica zawierająca 10 elementów, które są
wskaźniki do
char
Wartości.
Przykłady
Poniższe przykłady ilustrują inne złożone deklaracje i pokazują, jak nawiasy mogą wpływać na znaczenie deklaracji.
int *var[5]; /* Array of pointers to int values */
Modyfikator tablicy ma wyższy priorytet niż modyfikator wskaźnika, dlatego var
jest zadeklarowany jako tablica. Modyfikator wskaźnika ma zastosowanie do typu elementów tablicy; dlatego elementy tablicy są wskaźnikami do int
wartości.
int (*var)[5]; /* Pointer to array of int values */
W tej deklaracji dla var
nawiasów dają modyfikator wskaźnika wyższy priorytet niż modyfikator tablicy i var
jest deklarowany jako wskaźnik do tablicy pięciu int
wartości.
long *var( long, long ); /* Function returning pointer to long */
Modyfikatory funkcji mają również wyższy priorytet niż modyfikatory wskaźnika, więc ta deklaracja var
dla deklaracji var
jest funkcją zwracającą long
wskaźnik do wartości. Funkcja jest zadeklarowana, aby przyjmować dwie long
wartości jako argumenty.
long (*var)( long, long ); /* Pointer to function returning long */
Ten przykład jest podobny do poprzedniego. Nawiasy dają modyfikator wskaźnika wyższy priorytet niż modyfikator funkcji i var
jest deklarowany jako wskaźnik do funkcji zwracającej long
wartość. Ponownie funkcja przyjmuje dwa long
argumenty.
struct both /* Array of pointers to functions */
{ /* returning structures */
int a;
char b;
} ( *var[5] )( struct both, struct both );
Elementy tablicy nie mogą być funkcjami, ale ta deklaracja pokazuje, jak zadeklarować tablicę wskaźników do funkcji. W tym przykładzie var
zadeklarowana jest tablica pięciu wskaźników do funkcji, które zwracają struktury z dwoma składowymi. Argumenty funkcji są deklarowane jako dwie struktury o tym samym typie struktury: both
. Należy pamiętać, że nawiasy otaczające *var[5]
są wymagane. Bez nich deklaracja jest nielegalną próbą zadeklarowania tablicy funkcji, jak pokazano poniżej:
/* ILLEGAL */
struct both *var[5](struct both, struct both);
Poniższa instrukcja deklaruje tablicę wskaźników.
unsigned int *(* const *name[5][10] ) ( void );
Tablica name
zawiera 50 elementów zorganizowanych w tablicy wielowymiarowej. Elementy są wskaźnikiem do wskaźnika, który jest stałą. Ten stały wskaźnik wskazuje funkcję, która nie ma parametrów i zwraca wskaźnik do niepodpisanego typu.
W następnym przykładzie jest funkcja zwracająca wskaźnik do tablicy trzech double
wartości.
double ( *var( double (*)[3] ) )[3];
W tej deklaracji funkcja zwraca wskaźnik do tablicy, ponieważ funkcje zwracające tablice są niedozwolone. W tym miejscu var
zadeklarowana jest funkcja zwracająca wskaźnik do tablicy trzech double
wartości. Funkcja var
przyjmuje jeden argument. Argument, taki jak wartość zwracana, jest wskaźnikiem do tablicy trzech double
wartości. Typ argumentu jest podawany przez złożony deklarator abstrakcyjny. Nawiasy wokół gwiazdki w typie argumentu są wymagane; bez nich typ argumentu będzie tablicą trzech wskaźników do double
wartości. Aby zapoznać się z omówieniem i przykładami deklaratorów abstrakcyjnych, zobacz Deklaratory abstrakcyjne.
union sign /* Array of arrays of pointers */
{ /* to pointers to unions */
int x;
unsigned y;
} **var[5][5];
Jak pokazano w powyższym przykładzie, wskaźnik może wskazywać inny wskaźnik, a tablica może zawierać tablice jako elementy. Oto var
tablica pięciu elementów. Każdy element jest tablicą wskaźników z pięcioma elementami, aby wskazać wskaźniki do związków z dwoma elementami członkowskimi.
union sign *(*var[5])[5]; /* Array of pointers to arrays
of pointers to unions */
W tym przykładzie pokazano, jak umieszczanie nawiasów zmienia znaczenie deklaracji. W tym przykładzie var
jest tablica z pięcioma elementami wskaźników do tablic pięcioelementowych wskaźników do związków. Przykłady użycia typedef
w celu uniknięcia złożonych deklaracji można znaleźć w temacie Typedef Deklaracje.