Quel est le but de ce [1] à la fin de la déclaration struct?

96

J'étais en train de fouiner dans les fichiers d'en-tête de mon microcontrôleur MSP430, et je suis tombé sur ceci dans <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 */

Je comprends qu'il déclare une structure anonyme et qu'il est typedef jmp_buf, mais je ne peux pas comprendre à quoi cela [1]sert. Je sais qu'il déclare jmp_bufêtre un tableau avec un membre (de cette structure anonyme), mais je ne peux pas imaginer à quoi il sert. Des idées?

Alexander - Réintégrer Monica
la source
5
Quelque chose à voir avec la décomposition en pointeur peut-être?
Elazar
3
Le dernier commentaire semble totalement faux ...
R .. GitHub STOP HELPING ICE

Réponses:

115

C'est une astuce courante pour créer un "type de référence" en C, où son utilisation comme argument de fonction provoque la dégradation du tableau d'élément unique en un pointeur vers son premier élément sans que le programmeur ait besoin d'utiliser explicitement l' &opérateur pour obtenir son adresse. Lorsqu'elle est déclarée, c'est un vrai type de pile (aucune allocation dynamique nécessaire), mais lorsqu'elle est passée en argument, la fonction appelée reçoit un pointeur vers elle, pas une copie, donc elle est passée à bas prix (et peut être mutée par la fonction appelée sinon const).

GMP utilise la même astuce avec son mpz_ttype, et c'est critique là-bas, car la structure gère un pointeur vers la mémoire allouée dynamiquement; la mpz_initfonction repose sur l'obtention d'un pointeur vers la structure, pas une copie de celle-ci, ou elle n'a pas pu l'initialiser du tout. De même, de nombreuses opérations peuvent redimensionner la mémoire allouée dynamiquement, et cela ne fonctionnerait pas si elles ne pouvaient pas muter la structure de l'appelant.

ShadowRanger
la source
12
Il empêche également la copie via =.
melpomene
11
C'est dégoutant. J'accepterai cette réponse une fois le temps minimum écoulé. Merci de votre aide!
Alexander - Réintègre Monica
3
@Alexander: Ce n'est pas si dégoûtant une fois encapsulé via un typedefcomme ça. Ouais, faire cela ad-hoc serait un peu terrible, mais si vous avez un type légèrement opaque, où l'utilisateur de l'API n'a jamais besoin de penser à la sémantique de référence par rapport à la sémantique sans référence (cela devrait toujours passer par référence), c'est un moyen raisonnable d'ajouter une sémantique de référence automatique à un langage qui en manque autrement. Cela fonctionne même si l'utilisateur écrit ses propres API qui reçoivent le type, car en C, déclarer que vous acceptez un tableau comme argument signifie vraiment que vous acceptez un pointeur; tout "fonctionne juste".
ShadowRanger
4
@ShadowRanger C'est une astuce intelligente, mais ... otherwise lacks itc'est ce qui est dégoûtant. Les limites de C, pas la solution de contournement elle
Alexander - Réintégrer Monica
34
IMO c'est dégoûtant. La première fois que je travaillais avec GMP, je ne pouvais pas comprendre comment cela fonctionnait car les chiffres étaient apparemment passés par valeur. J'ai dû creuser dans les en-têtes GMP pour le résoudre. Cela va juste à l'encontre des gens qui connaissent déjà C. Ensuite, vous devez garder une trace mentale des paramètres qui sont passés par valeur et qui sont des références au lieu de simplement rechercher un *dans le code.
MM