Some questions about a single instance array in typedef

I was looking at some code using arbitrary length integers using the GNU Multi-Precision (GMP) library code. The type for the integer MP is mpz_t , as defined in the gmp.h header file.

But I have some questions about the child definition of this type of mpz_t library. In the header code:

 /* 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]; 

First question: is [1] __mpz_struct to __mpz_struct ? In other words, is there a typedef defining the type mpz_t as an __mpz_struct array with a single occurrence?

Second question: why an array? (And why only one event?) Is this one of those struct hacks I've heard of?

Third question (possibly indirectly related to the second question): The GMP documentation for the mpz_init_set(mpz_t, unsigned long int) function mpz_init_set(mpz_t, unsigned long int) says that it should be used only as a throughput, although it can be assumed that this function will change its contents inside the called function (and therefore, you need to pass by reference) syntax. Refer to my code:

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

Is a one-entry array automatically included by reference (due to breaking the semantics of the array / pointer to C)? I freely admit that I overdid it a bit, but of course I will love the discussion of this. Thanks!

+8
c arrays struct typedef gmp
source share
3 answers

* First question: does [1] bind to __mpz_struct? In other words, is it a typedef defining the type mpz_t as a single occurrence __mpz_struct array? *

Yes.

Second question: why an array? (And why only one event?) Is this one of those structural hacks I've heard of?

Hit me. I don’t know, but one of the possibilities is that the author wanted to make an object that was transferred by reference automatically, or “yes”, possibly a structural hack. If you have ever seen the mpz_t object as the last member of the structure, then "almost certainly" these are hackers. Distribution looks like

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

will be a dead sacrifice.

Is a one-entry array automatically included by reference ...?

Yeah, you get that too. “Yes”, one of the possible reasons is to simplify the transfer by link due to more complex links.

I believe another possibility is that something has changed in the data model or algorithm, and the author wanted to find any link and somehow change it. A type change like this would leave the program with the same base type, but with an error outside of every uncured link.

+3
source share

This is not like structural hacking in the sense described in C2. It seems like they want mpz_t have pointer semantics (presumably they want people to use it as an opaque pointer). Consider the syntactic difference between the following snippets:

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

and

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

Since C-arrays break up into pointers, this also allows you to automatically pass by reference for type mpz_t .

It also allows you to use a pointer type without requiring malloc or free .

+4
source share

The reason for this is the implementation of mpn . In particular, if you are mathematically inclined, you will understand that N is the set of natural numbers (1,2,3,4 ...), while Z is the set of integers (..., - 2, -1,0 1 , 2, ...).

The implementation of the bignum library for Z is equivalent to doing this for N and taking into account some special rules for operations with signs, i.e. tracking whether addition or subtraction is needed and what the result is.

Now about how the bignum library is implemented ... here is a line that will give you the key:

 typedef unsigned int mp_limb_t; typedef mp_limb_t * mp_ptr; 

And now let's look at the function signature acting on this:

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

Basically, it is that the "limb" is an integer field representing the bits of a number, and the integer is represented as a huge array. The smart part is that gmp does it all in a very efficient, well-optimized way.

In any case, back to the discussion. In principle, the only way to pass arrays to C, as you know, is to pass pointers to those arrays that effectively allow passing by reference. Now, to track what’s happening, two types are mp_ptr : mp_ptr , which is an array of mp_limb_t large enough to hold your number, and mp_srcptr , which is a version of const, so you can’t accidentally change the bits of the original bonuses to you are working. The basic idea is that most functions follow this pattern:

 func(ptr output, src in1, src in2) 

etc .. Thus, I suspect that the mpz_* functions follow this convention simply in order to be consistent, and that is because the authors think so.

Short version: due to how you need to implement bignum lib, this is necessary.

+2
source share

All Articles