Насколько я понимаю, 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);