Qual é o propósito disso [1] no final da declaração de struct?

96

Eu estava bisbilhotando os arquivos de cabeçalho do meu microcontrolador MSP430 e me deparei com o seguinte <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 */

Eu entendo que ele declara uma estrutura anônima e o digita jmp_buf, mas não consigo descobrir para que [1]serve. Eu sei que declara jmp_bufser uma matriz com um membro (desta estrutura anônima), mas não consigo imaginar para que é usado. Alguma ideia?

Alexander - Reintegrar Monica
fonte
5
Algo a ver com decair em ponteiro, talvez?
Elazar
3
O comentário final parece totalmente errado ...
R .. GitHub PARE DE AJUDAR O ICE

Respostas:

115

Este é um truque comum para fazer um "tipo de referência" em C, onde usá-lo como um argumento de função faz com que a matriz de elemento único se transforme em um ponteiro para seu primeiro elemento sem que o programador precise usar explicitamente o &operador para obter seu endereço. Onde declarado, é um tipo de pilha real (sem necessidade de alocação dinâmica), mas quando passado como um argumento, a função chamada recebe um ponteiro para ela, não uma cópia, então é passado barato (e pode ser modificado pela função chamada se não const)

O GMP usa o mesmo truque com seu mpz_ttipo, e é crítico nisso, porque a estrutura gerencia um ponteiro para a memória alocada dinamicamente; a mpz_initfunção depende de obter um ponteiro para a estrutura, não uma cópia dela, ou não poderia inicializá-la de forma alguma. Da mesma forma, muitas operações podem redimensionar a memória alocada dinamicamente e isso não funcionaria se não pudessem alterar a estrutura do chamador.

ShadowRanger
fonte
12
Também evita a cópia via =.
melpomene
11
Isso é nojento. Aceitarei essa resposta assim que o tempo mínimo terminar. Obrigado pela ajuda!
Alexander - Reintegrar Monica em
3
@Alexander: Não é tão grosseiro quando encapsulado por meio de um typedefcomo este. Sim, fazer isso ad-hoc seria terrível, mas se você tiver um tipo ligeiramente opaco, onde o usuário da API nunca precisa pensar sobre semântica de referência vs. sem referência (deve sempre passar por referência), é uma maneira razoável de adicionar semântica de referência automática a uma linguagem que, de outra forma, não a possui. Funciona até mesmo se o usuário escrever suas próprias APIs que recebem o tipo, porque em C, declarar que você aceita um array como um argumento realmente significa que você aceita um ponteiro; tudo "simplesmente funciona".
ShadowRanger
4
@ShadowRanger É um truque inteligente, mas ... otherwise lacks ité o que é nojento. As limitações do C, não a solução alternativa em si
Alexander - Reintegrar Monica
34
IMO é nojento. Na primeira vez que trabalhei com GMP não consegui entender como funcionava, pois os números eram aparentemente passados ​​por valor. Eu tive que cavar nos cabeçalhos GMP para decifrar. Isso simplesmente vai na cara das pessoas que realmente já conhecem C. Em seguida, você deve manter o controle mental de quais parâmetros são passados ​​por valor e quais são referência, em vez de apenas procurar *no código.
MM