Define struct in the heap with different sizes

165 Views Asked by At

I am trying to implement a bigInt library. I have been checking other libraries like GMP, ttmaht or libtommath but any of them fulfill the requirements of the project (because licenses, because they only use the stack, etc)

I will follow the approach of libtommath (really well documented and written all in C) but I want all stored in the heap. libtommath implements bigInt in an structure like this one:

typedef struct  {
    int used, alloc, sign;
    mp_digit *dp;
} mp_int;

As you can see it has an indirection for accessing the values. (mp_digit are the digits of the big integer). I want to get off the indirection so have some kind of similar struct in the heap where the last element is a mp_digit[] where the size can be different for each instance of mp_int.

I could do it using void* and malloc() knowing that the first X positions are int's with information (used, alloc, sign, etc) and then access to the mp_digit[] knowing the offset but I do not like this idea. I wonder which would be a better approach.

I found other similar questions like this one or this one but they do not store all in the heap so mine is a bit tricky/different.

Thank you,

2

There are 2 best solutions below

4
On

in C something like this to create

mp_int *LN_Create(int ndigits, int allocate)
{
    mp_int *ln = calloc(1, sizeof mp_int);

    if (ln != NULL)
    {
        ln->ndigits = ndigits;
        if (allocate)
        {
            ln->dp = calloc(ndigits, sizeof mp_digit);
            ln->alloc = 1;
            if (ln->dp == NULL)
            {
                free(ln);
                ln = NULL;
            }
        }
    }
    return ln;
}

or

mp_int *LN_Create1(int ndigits)
{
    size_t allocsize = sizeof mp_int + (ndigits - 1) * sizeof mp_digit;
    mp_int *ln = malloc(allocsize);

    if (ln != NULL)
    {
        memset(ln, 0, allocsize);
        ln->ndigits = ndigits;
    }
    return ln;
}
0
On

In C, mp_digit dp[] will mean a flexible array member. This appeared in C99:

typedef struct  {
    int used, alloc;
    signed char sign;
    mp_digit dp[];
} mp_int;

You can allocate memory with malloc(sizeof(mp_int) + alloc * sizeof(mp_digit));; also with realloc.

However there is an obscure thing that might help you save a byte or two here depending on the type of mp_digit - namely, the offset of dp isn't necessarily sizeof(mp_int) but might be less; there is a kludgey macro hack for calculating the actual minimum size to allocate (yet this is still portable).

That definition doesn't work in C++, but you could use a pointer to an incomplete type in C++.


Notice that a flexible array member is not compatible with an 1-byte array such as in here