From what I understand, mpz_t
are nothing but a single-item array.
According to 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];
That means that, given the way C handles arrays, mpz_t is effectively a pointer itself (to the first element of the one-element array).
Now, let's say I create a new mpz_t
, within a function, "box" the pointer in an unsigned long long and return, then... chaos. (Since, I guess, the pointer is no longer valid?)
The only way I could in theory make it work is by moving the mpz_t
declaration outside the function body (basically, make it a global)
Any other - more sensible - ideas?
Minimal example:
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));
}
Output:
3 + 5 = normal addition
3
2b + 2b = overflow
4000000000
pointer: 0x7ffee5b95630
overflow
4111111111
pointer: 0x7ffee5b95630
As you can see, the returned pointer is... the same. Although I would expect a different one.
UPDATE no 2
I'm currently thinking of doing it like this: (I'll see how it goes and then post it as a solution myself)
mpz_t* ret = malloc(sizeof(mpz_t));
mpz_init_set_si(*ret,a);
mpz_add_ui(*ret,*ret,b);
return toG(ret);