Marco
Marco

Reputation: 7287

Single malloc call for multiple data structures

Given the following structure:

struct myStructure {
    float                  myField;
};

struct mySecondStructure {
    int                    myField;
    struct myStructure     *mySecondField;
};

How can I efficiently allocate the struct mySecondStructure on the heap? (With the variable mySecondField initialized to a valid memory address)

I came up with two ways doing this:

First approach: use two calls to malloc:

struct mySecondStructure *structure = malloc(sizeof(* structure));
structure->mySecondField            = malloc(sizeof(* structure->mySecondField));

Second approach: use one call to malloc with enough space for both structures:

struct mySecondStructure *structure = malloc(sizeof(struct myStructure) + sizeof(struct mySecondStructure));
structure->mySecondField            = (struct myStructure *)(((unsigned char *)structure) + sizeof(struct mySecondStructure)); // the pointer points now to the end of the first structure

But the first one is in my opinion inefficient since it uses two calls to malloc. However I'm not sure if the second one will work properly because of data alignment.

Can someone enlighten me about this?

I'm thankful for any given help.

Upvotes: 1

Views: 1098

Answers (3)

mafso
mafso

Reputation: 5543

Depending on the members of the structures, it's possible that they have different alignment requirements. With C11, these requirements can be inspected with _Alignof (also related: _Alignas, max_align_t, <stdalign.h>).

A portable solution (also for C99) would be to add padding manually, something along the following:

struct mySecondStructure *structure;
size_t secondAlign  = sizeof *structure->mySecondField;
size_t offset       = (sizeof *structure + secondAlign - 1) / secondAlign
                      * secondAlign;
size_t total        = offset + sizeof *structure->mySecondField;
structure                   = malloc(total);
structure->mySecondField    = (void *)((char *)structure + offset);

With C11,

size_t secondAlign = _Alignof(struct myStructure);

also yields a valid (possibly smaller) result.

Otherwise, I agree with the others' comments and answers that this looks like premature optimization. What perhaps could be done now, however, is thinking about how changes in the allocation strategy may influence other peaces of the code and trying to keep such inter-dependencies to a minimum in order to allow later changes if this turns out to be worth it (e.g. if it should be possible to partially release memory, as covered in Scott's answer).

Upvotes: 2

Rob
Rob

Reputation: 1974

Both your approaches would work.

The difference between one malloc() call and two depends on how malloc() itself is implemented - which varies between implementations, is affected by operating system and hardware characteristics.

Without measuring the difference for your implementation, in the context of your program, and a typical execution environment (operating system, hardware, etc) all you are doing is indulging in premature optimisation.

Generally speaking, it would be better to do things in a way that are easier to understand (less complex code), easier to get right, and therefore easier to maintain. Then, if performance is a concern, do measurements to work out the bottlenecks.

In practice, you might also want to consider having a struct myStructure within your struct mySecondStructure, rather than a pointer [which is what Joachim's comment is about]. That way, you can allocate with a single malloc() call, without any need for additional bookkeeping to initialise pointers. Simpler to implement, easier to understand, and - if number of malloc() calls really matters - minimises that number.

Upvotes: 1

Scott Hunter
Scott Hunter

Reputation: 49896

The second approach should work; structs are padded so that they align properly (for example, consider if you had an array of them). One downside to the second approach would be if you wanted to reclaim the second structure (there is a reason its not just embedded in the first structure, I presume).

But the first is a lot cleaner, and what benefits there are to the second are minimal at best.

Upvotes: 1

Related Questions