Was ist der Zweck dieser [1] am Ende der Strukturdeklaration?

96

Ich habe die Header-Dateien meines MSP430-Mikrocontrollers durchsucht und bin auf Folgendes gestoßen <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 */

Ich verstehe, dass es eine anonyme Struktur deklariert und es typisiert jmp_buf, aber ich kann nicht herausfinden, wofür das [1]ist. Ich weiß, dass es jmp_bufsich um ein Array mit einem Mitglied (dieser anonymen Struktur) handelt, aber ich kann mir nicht vorstellen, wofür es verwendet wird. Irgendwelche Ideen?

Alexander - Monica wieder einsetzen
quelle
5
Hat das vielleicht etwas damit zu tun, in einen Zeiger zu verfallen?
Elazar
3
Der letzte Kommentar scheint völlig falsch ...
R .. GitHub STOP HELPING ICE

Antworten:

115

Dies ist ein gängiger Trick, um einen "Referenztyp" in C zu erstellen, bei dem die Verwendung als Funktionsargument dazu führt, dass sich das einzelne Elementarray zu einem Zeiger auf sein erstes Element verschlechtert, ohne dass der Programmierer den &Operator explizit verwenden muss , um seine Adresse abzurufen. Wo deklariert, handelt es sich um einen echten Stapeltyp (keine dynamische Zuordnung erforderlich), aber wenn die aufgerufene Funktion als Argument übergeben wird, erhält sie einen Zeiger darauf, keine Kopie, sodass sie kostengünstig übergeben wird (und von der aufgerufenen Funktion mutiert werden kann, wenn nicht const).

GMP verwendet denselben Trick für seinen mpz_tTyp und ist dort von entscheidender Bedeutung, da die Struktur einen Zeiger auf dynamisch zugewiesenen Speicher verwaltet. Die mpz_initFunktion basiert darauf, einen Zeiger auf die Struktur zu erhalten, keine Kopie davon, oder sie konnte sie überhaupt nicht initialisieren. In ähnlicher Weise können viele Vorgänge die Größe des dynamisch zugewiesenen Speichers ändern, und das würde nicht funktionieren, wenn sie die Struktur des Aufrufers nicht mutieren könnten.

ShadowRanger
quelle
12
Es verhindert auch das Kopieren über =.
Melpomene
11
Das ist eklig. Ich werde diese Antwort akzeptieren, sobald die Mindestzeit abgelaufen ist. Danke für Ihre Hilfe!
Alexander - Monica
3
@Alexander: Es ist nicht ganz so eklig, wenn es über so etwas eingekapselt wird typedef. Ja, dies ad-hoc zu tun wäre ein bisschen schrecklich, aber wenn Sie einen leicht undurchsichtigen Typ haben, bei dem der API-Benutzer nie über Referenz- oder Nicht-Referenz-Semantik nachdenken muss (es sollte immer als Referenz übergeben werden), ist dies ein vernünftiger Weg Hinzufügen einer automatischen Referenzsemantik zu einer Sprache, der sie sonst fehlt. Es funktioniert sogar, wenn der Benutzer seine eigenen APIs schreibt, die den Typ erhalten, da in C die Erklärung, dass Sie ein Array als Argument akzeptieren, wirklich bedeutet, dass Sie einen Zeiger akzeptieren. alles "funktioniert einfach".
ShadowRanger
4
@ShadowRanger Es ist ein kluger Trick, aber das ... otherwise lacks itist das Grobe daran. Die Einschränkungen von C, nicht die Problemumgehung selbst
Alexander - Reinstate Monica
34
IMO ist es eklig. Als ich das erste Mal mit GMP arbeitete, konnte ich nicht verstehen, wie es funktionierte, da die Zahlen anscheinend als Wert übergeben wurden. Ich musste mich in die GMP-Header vertiefen, um es herauszufinden. Es fliegt nur angesichts von Leuten, die C bereits kennen. Dann müssen Sie im Kopf verfolgen, welche Parameter als Wert übergeben werden und welche als Referenz dienen, anstatt nur nach einem *im Code zu suchen .
MM