Reputation: 7287
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
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
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
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