¿Cuál es el propósito de este [1] al final de la declaración de estructura?

96

Estaba husmeando en los archivos de encabezado de mi microcontrolador MSP430 y me encontré con esto 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 */

Entiendo que declara una estructura anónima y typedef jmp_buf, pero no puedo entender para qué [1]sirve. Sé que declara jmp_bufser una matriz con un miembro (de esta estructura anónima), pero no puedo imaginar para qué se usa. ¿Algunas ideas?

Alexander - Reincorporar a Monica
fuente
5
¿Algo que ver con la descomposición en puntero quizás?
Elazar
3
El comentario final parece totalmente equivocado ...
R .. GitHub dejar de ayudar a ICE

Respuestas:

115

Este es un truco común para hacer un "tipo de referencia" en C, donde usarlo como un argumento de función hace que la matriz de un solo elemento se degrade a un puntero a su primer elemento sin que el programador necesite usar explícitamente el &operador para obtener su dirección. Donde se declara, es un tipo de pila real (no se necesita asignación dinámica), pero cuando se pasa como un argumento, la función llamada recibe un puntero, no una copia, por lo que se pasa de forma económica (y puede ser mutada por la función llamada si no const).

GMP usa el mismo truco con su mpz_ttipo, y es crítico allí, porque la estructura administra un puntero a la memoria asignada dinámicamente; la mpz_initfunción se basa en obtener un puntero a la estructura, no una copia de ella, o no podría inicializarla en absoluto. De manera similar, muchas operaciones pueden cambiar el tamaño de la memoria asignada dinámicamente, y eso no funcionaría si no pudieran mutar la estructura del llamador.

ShadowRanger
fuente
12
También evita la copia a través de =.
melpomene
11
Eso es bruto. Aceptaré esta respuesta una vez que transcurra el tiempo mínimo. ¡Gracias por tu ayuda!
Alexander - Reincorpora a Monica
3
@Alexander: No es tan asqueroso cuando se encapsula a través de un dispositivo typedefcomo este. Sí, hacer esto ad-hoc sería un poco terrible, pero si tiene un tipo ligeramente opaco, donde el usuario de la API nunca necesita pensar en la semántica de referencia frente a la no referencia ( siempre debe pasar por referencia), es una forma razonable de agregar semántica de referencia automática a un lenguaje que de otra manera carece de ella. Incluso funciona si el usuario escribe sus propias API que reciben el tipo, porque en C, declarar que acepta una matriz como argumento realmente significa que acepta un puntero; todo "simplemente funciona".
ShadowRanger
4
@ShadowRanger Es un truco inteligente, pero ... otherwise lacks ites lo más asqueroso. Las limitaciones de C, no la solución en sí misma
Alexander - Reincorporar a Monica
34
En mi opinión, es asqueroso. La primera vez que trabajé con GMP no pude entender cómo funcionaba ya que los números aparentemente se pasaban por valor. Tuve que profundizar en los encabezados de GMP para descifrarlo. Simplemente vuela en la cara de las personas que realmente conocen a C ya. Luego, debe realizar un seguimiento mental de qué parámetros se pasan por valor y cuáles son referencia en lugar de simplemente buscar un *en el código.
MM