关于typedef中单实例数组的一些问题

我正在使用GNU Multi-Precision(GMP)库代码使用任意长度的整数来阅读一些代码。 MP整数的类型是mpz_t如gmp.h头文件中所定义。

但是,我对这个库定义的mpz_t类型的低级定义有一些疑问。 在标题代码中:

 /* THIS IS FROM THE GNU MP LIBRARY gmp.h HEADER FILE */ typedef struct { /* SOME OTHER STUFF HERE */ } __mpz_struct; typedef __mpz_struct mpz_t[1]; 

第一个问题: [1]是否与__mpz_struct相关联? 换句话说, typedef是将mpz_t类型定义为__mpz_struct数组,只出现一次?

第二个问题:为什么arrays? (为什么只出现一次?)这是我听说过的结构黑客之一吗?

第三个问题(可能与第二个问题间接相关): mpz_init_set(mpz_t, unsigned long int)函数的GMP文档说只使用它作为pass-by-value,尽管可以假设这个函数会修改其内容被调用的函数(因此需要pass-by-reference)语法。 参考我的代码:

 /* FROM MY CODE */ mpz_t fact_val; /* declaration */ mpz_init_set_ui(fact_val, 1); /* Initialize fact_val */ 

单次出现数组是否允许自动传递引用(由于C中数组/指针语义的崩溃)? 我坦率地承认我有点过分分析这个,但我当然喜欢对此进行任何讨论。 谢谢!

* 第一个问题: [1]是否与__mpz_struct相关联? 换句话说,typedef是将mpz_t类型定义为__mpz_struct数组,只出现一次? *

是。

第二个问题:为什么arrays? (为什么只出现一次?)这是我听说过的结构黑客之一吗?

甘拜下风。 不知道,但有一种可能性是作者想要创建一个通过引用自动传递的对象,或者“是”,可能是struct hack。 如果你曾经看到一个mpz_t对象作为结构的最后一个成员,那么“几乎可以肯定”它就是struct hack。 分配看起来像

 malloc(sizeof(struct whatever) + sizeof(mpz_t) * some_number)` 

将是一个死的赠品。

单次出现数组是否允许自动传递引用…?

啊哈,你也明白了。 “是”,一个可能的原因是以更复杂的引用为代价来简化传递引用。

我想另一种可能性是数据模型或算法中发生了某些变化,作者希望找到每个参考并以某种方式对其进行更改。 像这样的类型更改会使程序具有相同的基本类型,但每个未转换的引用都会出错。

在C2中描述的意义上,这似乎不是结构黑客。 看起来他们希望mpz_t具有指针语义(可能,他们希望人们像使用不透明指针一样使用它)。 考虑以下代码段之间的语法差异:

 struct __mpz_struct data[1]; (&data[0])->access = 1; gmp_func(data, ...); 

 mpz_t data; data->access = 1; gmp_func(data, ...); 

因为C数组衰减成指针,所以这也允许mpz_t类型的引用自动传递。

它还允许您使用类似指针的类型,而无需mallocfree它。

其原因来自mpn的实现。 具体来说,如果你在数学上倾斜,你会发现N是自然数的集合(1,2,3,4 …)而Z是整数集(…, – 2,-1,0) ,1,2,…)。

为Z实现bignum库等同于对N执行此操作并考虑到符号操作的一些特殊规则,即跟踪是否需要执行加法或减法以及结果是什么。

现在,关于如何实现bignum库…这里有一条线给你一个线索:

 typedef unsigned int mp_limb_t; typedef mp_limb_t * mp_ptr; 

现在让我们看一下在其上运行的函数签名:

 __GMP_DECLSPEC mp_limb_t mpn_add __GMP_PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr,mp_size_t)); 

基本上,它归结为“肢体”是表示数字位的整数字段,整数表示为一个巨大的数组。 聪明的部分是gmp以非常有效,优化的方式完成所有这些工作。

无论如何,回到讨论。 基本上,如你所知,在C中传递数组的唯一方法是将指针传递给那些有效地通过引用传递的数组。 现在,为了跟踪发生了什么,定义了两种类型,一个mp_ptr ,一个mp_ptr数组,足以存储你的数字, mp_srcptr是一个const版本,所以你不能不小心改变这些位关于你正在经营什么的源bignums。 基本思想是大多数函数都遵循这种模式:

 func(ptr output, src in1, src in2) 

因此,我怀疑mpz_*函数遵循这个约定只是为了保持一致,这是因为这就是作者的想法。

简短版本:由于你必须实现bignum lib,这是必要的。