结构声明结束时这[1]的目的是什么?

Ale*_*ica 95 c struct typedef reverse-engineering declaration

我正在窥探我的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 */
Run Code Online (Sandbox Code Playgroud)

我知道它声明了一个匿名结构和typedef它jmp_buf,但我无法弄清楚它是什么[1].我知道它声明jmp_buf是一个有一个成员(这个匿名结构)的数组,但我无法想象它用于什么.有任何想法吗?

Sha*_*ger 113

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

GMP在其mpz_t类型中使用相同的技巧,并且它在那里至关重要,因为该结构管理指向动态分配的内存的指针; 该mpz_init函数依赖于获取指向结构的指针,而不是它的副本,或者它根本无法初始化它.类似地,许多操作可以调整动态分配的内存的大小,如果它们不能改变调用者的结构,则无法工作.

  • IMO很糟糕.第一次使用GMP我无法理解它是如何工作的,因为数字显然是通过价值传递的.我不得不深入研究GMP标题以解决它.它只是面对那些实际上已经知道C的人.然后你必须记住哪些参数是通过值传递的,哪些是引用,而不是仅仅在代码中查找`*`. (34认同)
  • 它还可以防止通过`=`进行复制. (12认同)
  • 真恶心.一旦最小时间过去,我会接受这个答案.谢谢你的帮助! (11认同)
  • @ShadowRanger这是一个聪明的伎俩,但是`...否则缺乏它'就是它的重要性.C的局限性,而不是变通方法本身 (4认同)
  • @Alexander:当通过像这样的`typedef'封装时,它并不是那么糟糕.是的,做这个ad-hoc会有点可怕,但如果你有一个微弱的不透明类型,API用户永远不需要考虑引用与非引用语义(它应该*总是*通过引用传递),它是一个将自动引用语义添加到否则缺少它的语言的合理方法.它甚至可以在用户编写自己接收类型的API时工作,因为在C中,声明接受数组作为参数实际上意味着你接受了一个指针; 一切都"正常". (3认同)
  • @MM:看,我也以同样的方式感到困惑,并且也进行了调查,但是我对此的反应是欣赏它的聪明。对于GMP函数,所有的GMP类型参数都是通过引用传递的,因此没有太多的精神开销。除了自动按引用传递外,阻塞分配和按值传递还可以防止发生事故(其中两个`mpz_t`最终包含指向同一内存的指针,这可能会在其上获得`free`或`realloc`-ed。只有一个,留下垃圾指针)。即使是新手,也不会意外地执行“ mpz_t mpz2 = mpz2;”并破坏一切。 (2认同)