So recently I've been poking around in the internals of GMP for a project I'm working on, and I've encountered a construct that makes very little sense to me: (taken from the header for version 6.2.1)
/* For reference, note that the name __mpz_struct gets into C mangled
function names, which means although the "__" suggests an internal, we
must leave this name for binary compatibility. */
typedef struct
{
int _mp_alloc; /* Number of *limbs* allocated and pointed
to by the _mp_d field. */
int _mp_size; /* abs(_mp_size) is the number of limbs the
last field points to. If _mp_size is
negative this is a negative number. */
mp_limb_t *_mp_d; /* Pointer to the limbs. */
} __mpz_struct;
#endif /* __GNU_MP__ */
typedef __mpz_struct MP_INT; /* gmp 1 source compatibility */
typedef __mpz_struct mpz_t[1];
On the final line here, we typedef mpz_t
to be an array of size 1 containing __mpz_struct
s. This is very strange to me, and I've never seen a construction like this before. I understand that this results in mpz_t
effectively being a pointer to an __mpz_struct
, but is this equivalent or not to
typedef __mpz_struct* mpz_t;
Could somebody explain the logic behind this?
CodePudding user response:
With that typedef
, a variable declaration like
mpz_t foo;
is equivalent to
__mpz_struct foo[1];
This will only be converted to
__mpz_struct *foo;
if the declaration is in a function parameter list. Otherwise, it's a ordinary array declaration.
CodePudding user response:
Given typedef __mpz_struct mpz_t[1];
, you can declare an actual mpz_t
object with mpz_t foo;
. This will reserve memory for an mpz_t
.
In contrast, if the type were typedef __mpz_struct *mpz_t;
, then mpz_t foo;
would only give you a pointer. There would be no space for an mpz_t
. You would have to allocate it, and you would have to free it later. So more code is required, and it would be a nuisance.
At the same time, when an mpz_t
is passed to a function, only its address is passed, due to the automatic conversion of arrays to pointers. This allows writing mpz_add(z, x, y);
, which is less cluttered than mpz_add(&z, &x, &y);
. There may be arguments among programmers about whether it is bug-prone to use a type definition that effectively results in a reference to an object being passed to a function when the code nominally looks like just a value is passed, but this style may be more suitable for the type of programming done with GMP.