Possible side effects of doing a typedef of a struct to an array of one element in C
Asked Answered
D

4

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?

Dekaliter answered 27/5, 2015 at 9:57 Comment(8)
possible duplicate of Some questions about a single-instance array in typedefKeratoplasty
OT: Why couldn't you just pass the address of simple struct var using the &-operator?Raber
@Keratoplasty Thanks! That helps but only a part of the question. The side effects are unaswered.Dekaliter
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.Raber
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...Ubiquitous
@MarcGlisse Here is the link github.com/srawlins/gmp/blob/master/ext/ruby_gmp.h#L25Dekaliter
@Raber In your latest comment did you mean MP_INT some_variable; __mpz_struct * p = (&some_variable) + 1; because this would work.Dekaliter
I indeed ment MPINT some_variable;. This MP_INT * p = (&some_variable) + 1; however will invoke undefined bahaviour. @AbinashMeherRaber
R
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 ... ;-)

Raber answered 27/5, 2015 at 10:21 Comment(1)
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].iTotally
A
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.

Admittedly answered 27/5, 2015 at 10:17 Comment(3)
Nitpicking: "the name of an array "decays"" the name is gone after compilation, so the array "decays".Raber
well, yes, but to use it in an expression you have to use its name. But I'll rephrase a bit indeed.Admittedly
Who commented on my comment you or your name? ;-)Raber
R
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 ... ;-)

Raber answered 27/5, 2015 at 10:21 Comment(1)
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].iTotally
J
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.

Jacktar answered 20/3, 2017 at 11:14 Comment(0)
C
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.

Curvy answered 27/5, 2015 at 10:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.