Udostępnij za pośrednictwem


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:

  1. Zacznij od identyfikatora i spójrz bezpośrednio po prawej stronie nawiasów lub nawiasów (jeśli istnieją).

  2. Zinterpretuj te nawiasy lub nawiasy, a następnie poszukaj po lewej stronie gwiazdki.

  3. Jeśli napotkasz prawy nawias na dowolnym etapie, wróć i zastosuj reguły 1 i 2 do wszystkich elementów w nawiasach.

  4. 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:

  1. Identyfikator var jest zadeklarowany jako

  2. wskaźnik do

  3. funkcja zwracająca

  4. wskaźnik do

  5. tablica zawierająca 10 elementów, które są

  6. wskaźniki do

  7. 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 varnawiasó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.

Zobacz też

Deklaracje i typy