struct声明末尾的[1]的目的是什么?


96

我正在窥探MSP430微控制器的头文件,并且在<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 */

我知道它声明了一个匿名结构并将其类型定义为jmp_buf,但是我不知道它[1]是干什么的。我知道它声明jmp_buf是一个带有一个成员的数组(此匿名结构的成员),但是我无法想象它的用途。有任何想法吗?


5
可能与衰减到指针有关?
Elazar

3
最后的评论似乎是完全错误的……
R .. GitHub停止帮助ICE

Answers:


115

这是在C语言中创建“引用类型”的常见技巧,其中将其用作函数参数会导致单个元素数组退化为指向其第一个元素的指针,而程序员无需显式使用&运算符来获取其地址。在声明的地方,它是一个真正的堆栈类型(不需要动态分配),但是当作为参数传递时,被调用函数会收到指向它的指针,而不是副本,因此它被廉价地传递(如果没有,则可以由被调用函数进行突变const)。

GMP在mpz_t类型上使用了相同的技巧,在这里很关键,因为该结构管理着指向动态分配内存的指针。该mpz_init函数依赖于获取结构的指针,而不是结构的副本,或者根本无法初始化它。同样,许多操作可以调整动态分配的内存的大小,并且如果它们不能使调用者的结构发生变异,则该操作将无效。


12
它还可以防止通过复制=
melpomene

11
真恶心。最小时间过后,我会接受这个答案。谢谢你的帮助!
亚历山大-恢复莫妮卡

3
@Alexander:通过typedef这样的方式封装时,并不太复杂。是的,临时执行此操作会很糟糕,但是如果您的类型很模糊,API用户无需考虑引用和非引用语义(应该始终通过引用传递),这是一种合理的方法在没有其他语言的语言中添加自动引用语义的说明。如果用户编写自己的API来接收该类型,它甚至可以工作,因为在C语言中,声明您接受数组作为参数确实意味着您接受了指针。一切“正常”。
ShadowRanger

4
@ShadowRanger这是一个聪明的把戏,但这... otherwise lacks it是什么。C语言的局限性,而不是解决方法本身
亚历山大-恢复莫妮卡(Monica)

34
海事组织,这很严重。第一次使用GMP时,我无法理解它是如何工作的,因为数字显然是按值传递的。我不得不深入研究GMP标头以解决它。它只是在实际上已经知道C的人们面前飞逝。然后,您必须牢记哪些参数是通过值传递的,哪些是引用的,而不是仅*在代码中查找a 。
MM
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.