6

I came across this code.

typedef __mpz_struct MP_INT;
typedef __mpz_struct mpz_t[1];

Here the struct __mpz_struct is a struct that is typedefed to an array of single element. I understand that this is a trick to pass by reference in C. Then mpz_t has been used as a type to declare variables and pass them to function as parameters. Also, There was one more comment

/*
  MP_INT*, MP_RAT* and MP_FLOAT* are used because they don't have side-effects
  of single-element arrays mp*_t
*/

What kind of side effects are they talking about?

  • possible duplicate of [Some questions about a single-instance array in typedef](http://stackoverflow.com/questions/4835112/some-questions-about-a-single-instance-array-in-typedef) – ecatmur May 27 '15 at 10:06
  • OT: Why couldn't you just pass the address of simple `struct` var using the `&`-operator? – alk May 27 '15 at 10:14
  • @ecatmur Thanks! That helps but only a part of the question. The side effects are unaswered. – Abinash Meher May 27 '15 at 10:19
  • Regarding side-effect: `mpz_t m; __mpz_struct * p = &(m[0]) + 1;` would be valid, whereas `__mpz_struct MP_INT; __mpz_struct * p = (&MP_INT) + 1;` wouldn't. – alk May 27 '15 at 11:03
  • That doesn't seem to be part of the current GMP sources. It would help if you gave a precise link to the source of that quote so we can look at the context... – Marc Glisse May 27 '15 at 16:36
  • @MarcGlisse Here is the link https://github.com/srawlins/gmp/blob/master/ext/ruby_gmp.h#L25 – Abinash Meher May 28 '15 at 12:30
  • @alk In your latest comment did you mean `MP_INT some_variable; __mpz_struct * p = (&some_variable) + 1;` because this would work. – Abinash Meher May 28 '15 at 12:34
  • I indeed ment `MPINT some_variable;`. This `MP_INT * p = (&some_variable) + 1;` however will invoke undefined bahaviour. @AbinashMeher – alk May 28 '15 at 12:47

4 Answers4

2

I see two parts to your question. The first part, how the typedef works for passing arguments to functions, would better be illustrated with an example. Without it, I'll have to guess a bit.

In C function declarations, an array parameter is equivalent to a pointer. That's why you see (for example) equivalently for the main function,

int main(int argc, char **argv)

and

int main(int argc, char *argv[])

Similarly, if a function in your program would be declared

int func(__mpz_struct *arg)

it would be equivalent to

int func(__mpz_struct arg[])

and hence to

int func(mpz_t arg)

Also, on the calling side, if you have a variable of type mpz_t, hence the array, and you pass it to a function, the "pointer decay" takes effect: in an expression, if you use (the name of) an array it "decays" into a pointer to its first element. This way you can call the function:

mpz_t value;
func(value);

Of course, to modify these mpz_t objects outside of the API functions, you still have to be aware of their true nature.

The side effects that you mention, I would also have to guess about them. Possibly it is meant that you have to be aware you're working with pointers inside the functions. It might be considered better to make that explicit by using the pointer syntax.

Olaf Seibert
  • 151
  • 7
2

Passing an array to a function let's the array decay to a pointer to it's 1st element.

One can achieve the same effect by applying the Address-Of operator & to a simple variable of the same type as the array's elements.

Examples:

struct S
{
   int i;
   float f;
};

This

void set_S(struct S * ps)
{
  ps->i = 40;
  ps->f = 2.;
}

is equivalent to

void set_S(struct S ps[1])
{
  ps->i = 40;
  ps->f = 2.;
}

is equivalent to

void set_S(struct S * ps)
{
  ps[0].i = 40;
  ps[0].f = 2.;
}

is equivalent to

void set_S(struct S ps[1])
{
  ps[0].i = 40;
  ps[0].f = 2.;
}

One-Element-Array approach:

typedef struct S Array_of_S_with_size_1[1];

int main(void)
{
  Array_of_S_with_size_1 array_of_S_with_size_1;
  array_of_S_with_size_1[0].i = 0;
  array_of_S_with_size_1[0].f = 0.;

  set_S(array_of_S_with_size_1);

  ...
}

The above main() provides the same functionality as the following:

int main(void)
{
  struct S s;
  s.i = 0;
  s.f = 0.;

  set_S(&s);

  ...
}

I do not see any gain using the "One-Element-Array" approach. An expection might be if the &-key is broken on ones keyboard ... ;-)

alk
  • 69,737
  • 10
  • 105
  • 255
  • these two examples: void set_S(struct S * ps) { ps[0] = 40; ps[0] = 2.; } is equivalent to void set_S(struct S ps[1]) { ps[0] = 40; ps[0] = 2.; } are not correct. the field names need to be reference, like ps[0].f and ps[0].i – user3629249 May 28 '15 at 01:56
  • @user3629249: Fixed. Thanks! – alk May 28 '15 at 05:31
1

You can assign an MP_INT to another but you can not assign an mpz_t to another since assignment is not defined for arrays. If you do not want your clients to assign variables other than by your methods (which might do memory managements and stuff) this is the trick for you.

David
  • 11
  • 1
0

Look at this sample code

typedef char type24[3];

Same as your, but well known data type 'char' insted of your struct __mpz_struct type.

above type def means, I am using above typedef to represent char[3].

So in your sample code,

typedef __mpz_struct mpz_t[1];

mpz_t should be __mpz_struct type.

ANjaNA
  • 1,404
  • 2
  • 16
  • 29