Возможные побочные эффекты делать typedef для структуры в массив один элемент с


Я наткнулся на этот код.

typedef __mpz_struct MP_INT;
typedef __mpz_struct mpz_t[1];

Здесь структура __mpz_struct - это структура, которая типизирована в массив одного элемента. Я понимаю, что это трюк для передачи по ссылке в C. Затем mpz_t был использован в качестве типа для объявления переменных и передачи их в функцию в качестве параметров. Кроме того, был еще один комментарий

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

О каких побочных эффектах идет речь?

4 6

4 ответа:

Передавая массив в функцию, пусть массив распадается на указатель на его 1-й элемент.

Такого же эффекта можно достичь, применив оператор Address-Of & к простой переменной того же типа, что и элементы массива.

Примеры:

struct S
{
   int i;
   float f;
};

Это

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

Эквивалентно

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

Эквивалентно

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

Эквивалентно

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

Одноэлементный подход к массиву:

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);

  ...
}

Вышеуказанное main() обеспечивает те же функции, что и следующие:

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

  set_S(&s);

  ...
}

Я не вижу никакого усиления, используя подход " одноэлементный массив". Выражение может быть, если &-клавиша сломана на одной клавиатуре ... ;- )

Я вижу двух частей на ваш вопрос. Первую часть, как typedef работает для передачи аргументов в функции, лучше проиллюстрировать на примере. Без него мне придется немного догадаться.

В объявлениях функций C параметр массива эквивалентен указателю. Вот почему вы видите (например) эквивалентно для основной функции,

int main(int argc, char **argv)

И

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

Аналогично, если функция в вашей программе будет объявлена

int func(__mpz_struct *arg)

Это было бы эквивалентно

int func(__mpz_struct arg[])

И, следовательно, к

int func(mpz_t arg)

Кроме того, на вызывающей стороне, если у вас есть переменная типа mpz_t, следовательно, массив, и вы передаете ее функции," распад указателя "вступает в силу: в выражении, если вы используете (имя) массива, он" распадается " в указатель на его первый элемент. Таким образом, вы можете вызвать функцию:

mpz_t value;
func(value);

Конечно, чтобы модифицировать эти объекты mpz_t вне функций API, вы все равно должны знать об их истинном значении. природа.

Побочные эффекты, о которых вы упомянули, я также должен был бы догадаться о них. Возможно, это означает, что вы должны осознавать, что работаете с указателями внутри функций. Было бы лучше сделать это явным, используя синтаксис указателя.

Вы можете назначить MP_INT другому, но вы не можете назначить mpz_t другому, так как назначение не определено для массивов. Если вы не хотите, чтобы ваши клиенты назначали переменные, отличные от ваших методов (которые могут выполнять управление памятью и прочее), это трюк для вас.

Посмотрите на этот пример кода

typedef char type24[3];

То же, что и ваш, но хорошо известный тип данных 'char' вместо вашего типа struct __mpz_struct.

Выше типа def означает, что я использую выше typedef для представления char[3].

Итак, в вашем примере кода,

typedef __mpz_struct mpz_t[1];

mpz_t должно быть __mpz_struct типа.