Сохранение адреса mpz_t и передача указателя - PullRequest
0 голосов
/ 23 января 2020

Насколько я понимаю, mpz_t - это не что иное, как массив из одного элемента.

Согласно gmp.h :

{
  short int _mp_alloc;      /* Number of *limbs* allocated and pointed
                   to by the D field.  */
  short int _mp_size;       /* abs(SIZE) is the number of limbs
                   the last field points to.  If SIZE
                   is negative this is a negative
                   number.  */
  mp_limb_t *_mp_d;     /* Pointer to the limbs.  */
} __mpz_struct;

typedef __mpz_struct mpz_t[1];

Это означает, что Учитывая способ обработки массивов C, mpz_t фактически является указателем (на первый элемент одноэлементного массива).

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

Единственный способ теоретически заставить его работать, это переместить объявление mpz_t за пределы тела функции (в основном, сделать его глобальным).

Любые другие - более разумные - идеи?


Минимальный пример:

typedef uint64_t Value;

#define addWillOverflow(x,y,z) __builtin_sadd_overflow(x,y,z)

#define BITFIELD 56

#define MASK(x) ((Value)(x) << BITFIELD)
#define UNMASK  0x00FFFFFFFFFFFFFF

#define toI(v)  ( (Value)(v & 0xFFFFFFFFu) | MASK(IV) )
#define toG(v)  ( (Value)(v) | MASK(GV) )
#define GG(v)   ( (v & UNMASK) )

Value addNumbers(int a, int b) {
    Int32 res;
    if (addWillOverflow(a,b,&res)) {
        printf("overflow\n");
        mpz_t ret;
        mpz_init_set_si(ret,a);
        mpz_add_ui(ret,ret,b);
        return toG(ret);
    }
    else {
        printf("normal addition\n");
        return toI(res);
    }
}

int main(int argc, char** argv) {

    printf("3 + 5 = ");
    printLnValue(addNumbers(1,2));

    printf("2b + 2b = ");
    Value a = addNumbers(2000000000,2000000000);
    printLnValue(a);
    printf("pointer: %p\n",GG(a));

    Value b = addNumbers(2100000000,2011111111);
    printLnValue(b);
    printf("pointer: %p\n",GG(b));
}

Вывод:

3 + 5 = normal addition
3
2b + 2b = overflow
4000000000
pointer: 0x7ffee5b95630
overflow
4111111111
pointer: 0x7ffee5b95630

Как видите, возвращаемый указатель ... такой же. Хотя я бы ожидал другого.


ОБНОВЛЕНИЕ № 2

В настоящее время я думаю сделать это так: (Я посмотрю, как это заходит и потом выкладываю как решение сам)

    mpz_t* ret = malloc(sizeof(mpz_t));
    mpz_init_set_si(*ret,a);
    mpz_add_ui(*ret,*ret,b);
    return toG(ret);
...