Jaki jest cel tego [1] na końcu deklaracji struktury?

96

Szperałem w plikach nagłówkowych mojego mikrokontrolera MSP430 i natknąłem się na to w <setjmp.h>:

/* r3 does not have to be saved */
typedef struct
{
    uint32_t __j_pc; /* return address */
    uint32_t __j_sp; /* r1 stack pointer */
    uint32_t __j_sr; /* r2 status register */
    uint32_t __j_r4;
    uint32_t __j_r5;
    uint32_t __j_r6;
    uint32_t __j_r7;
    uint32_t __j_r8;
    uint32_t __j_r9;
    uint32_t __j_r10;
    uint32_t __j_r11;
} jmp_buf[1]; /* size = 20 bytes */

Rozumiem, że deklaruje anonimową strukturę i jest to typedef jmp_buf, ale nie mogę dowiedzieć się, do czego [1]służy. Wiem, że deklaruje, jmp_bufże jest tablicą z jednym elementem (tej anonimowej struktury), ale nie mogę sobie wyobrazić, do czego służy. Jakieś pomysły?

Alexander - Przywróć Monikę
źródło
5
Może to coś wspólnego z rozpadem na wskaźnik?
Elazar
3
Ostatni komentarz wydaje się całkowicie błędny ...
R .. GitHub STOP HELPING ICE

Odpowiedzi:

116

Jest to powszechna sztuczka przy tworzeniu „typu referencyjnego” w C, gdzie użycie go jako argumentu funkcji powoduje degradację tablicy jednoelementowej do wskaźnika do jej pierwszego elementu bez konieczności jawnego użycia &operatora w celu uzyskania jej adresu. Tam, gdzie jest zadeklarowany, jest to prawdziwy typ stosu (nie jest wymagana alokacja dynamiczna), ale gdy jest przekazywana jako argument, wywoływana funkcja otrzymuje wskaźnik do niej, a nie kopię, więc jest przekazywana tanio (i może zostać zmutowana przez wywołaną funkcję, jeśli nie const).

GMP używa tej samej sztuczki ze swoim mpz_ttypem i jest tam krytyczny, ponieważ struktura zarządza wskaźnikiem do dynamicznie przydzielanej pamięci; mpz_initfunkcja polega na uzyskiwanie wskaźnik do struktury, a nie kopia, lub nie może zainicjować go w ogóle. Podobnie, wiele operacji może zmienić rozmiar dynamicznie przydzielonej pamięci, a to nie zadziałałoby, gdyby nie mogły zmutować struktury wywołującego.

ShadowRanger
źródło
12
Zapobiega również kopiowaniu przez =.
melpomene
11
To obrzydliwe. Zaakceptuję tę odpowiedź po upływie minimalnego czasu. Dzięki za pomoc!
Alexander - Przywróć Monikę
3
@Alexander: To nie jest takie obrzydliwe, gdy jest zamknięte w typedeftaki sposób. Tak, zrobienie tego ad-hoc byłoby trochę okropne, ale jeśli masz lekko nieprzejrzysty typ, w którym użytkownik API nigdy nie musi myśleć o semantyce referencyjnej w porównaniu do semantyki bez referencji ( zawsze powinna być przekazywana przez referencję), jest to rozsądny sposób dodawania automatycznej semantyki odwołań do języka, który w innym przypadku jej nie ma. Działa nawet, jeśli użytkownik napisze własne API, które otrzymają typ, ponieważ w C deklaracja, że ​​akceptujesz tablicę jako argument, w rzeczywistości oznacza, że ​​akceptujesz wskaźnik; wszystko „po prostu działa”.
ShadowRanger
4
@ShadowRanger To sprytna sztuczka, ale ... otherwise lacks itjest w niej obrzydliwa. Ograniczenia C, a nie samo obejście
Alexander - Przywróć Monikę
34
IMO to obrzydliwe. Kiedy pierwszy raz pracowałem z GMP, nie mogłem zrozumieć, jak to działa, ponieważ liczby najwyraźniej były przekazywane według wartości. Musiałem zagłębić się w nagłówki GMP, aby to rozwiązać. Po prostu leci przed ludźmi, którzy faktycznie już znają C. Następnie musisz śledzić w pamięci, które parametry są przekazywane przez wartość, a które są odniesieniami, zamiast po prostu szukać *w kodzie.
MM