Is this how one can use the the \"extra\" memory allocated while using the C struct hack?
Questions:
I have a C struct hack implementation below. My questio
Yes, that is (and was) the standard way in C
to create and process a variably-sized struct
.
That example is a bit verbose. Most programmers would handle it more deftly:
struct mystruct {
int len;
char chararray[1]; // some compilers would allow [0] here
};
char *msg = "abcdefghi";
int n = strlen (msg);
struct mystruct *ptr = malloc(sizeof(struct mystruct) + n + 1);
ptr->len = n;
strcpy (ptr->chararray, msg);
}
It is 'correct', but you'd need a good reason to do that over a more reasonable solution. More commonly perhaps you'd use this technique to "overlay" some existing array to impose some sort of header structure on to it.
Note that GCC by extension allows a zero length array member for exactly this purpose, while ISO C99 "legitimises" the practice by allowing a member with empty brackets (only as the last member).
Note that there are some semantic issues - sizeof the struct will not of course account for the "flexible" size of the final member, and passing the struct "by value" will only pass the header and first element (or no element using the GCC extension or C99 flexible array member). Similarly direct struct assignment will not copy all the data.
Ever since I read this article (http://blogs.msdn.com/b/oldnewthing/archive/2004/08/26/220873.aspx), I've liked to use the struct hack like so:
#include<stdio.h>
#include<stdlib.h>
int main()
{
struct mystruct {
int len;
char chararray[1];
};
int number_of_elements = 10;
struct mystruct *ptr = malloc(offsetof(struct mystruct, chararray[number_of_elements]));
ptr->len = number_of_elements;
for (i = 0; i < number_of_elements; ++i) {
ptr->chararray[i] = 'a' + i;
}
}
I find that not having to remember whether 1 needs to be subtracted (or added or whatever) is nice. This also has the bonus of working in situations where 0
is used in the array definition, which not all compilers support but some do. If the allocation is based on offsetof()
you don't need to worry about that possible detail making your math wrong.
It also works without change is the struct is a C99 flexible array member.
I would advise against that due to possible alignment issues instead consider this:
struct my_struct
{
char *arr_space;
unsigned int len;
}
struct my_struct *ptr = malloc(sizeof(struct my_struct) + 10);
ptr->arr_space = ptr + 1;
ptr->len = 10;
This will give you locality as well as safety :) and avoid weird alignment issues.
By alignment issues I meant possible access delays for accessing unaligned memory.
In the original example if you add a byte or non word aligned member (byte, char, short) then the compiler may extend the size of the structure but as far as your pointer is concerned you are reading the memory directly after the end of the struct (non aligned). This means if you have an array of an aligned type such as int
every access will net you a performance hit on CPUs that take hits from reading unaligned memory.
struct
{
byte_size data;
char *var_len;
some_align added by compiler;
}
In the original case you will be reading from the some_align
region which is just filler but in my case you will read from aligned extra memory afterwards (which wastes some space but that's typically okay).
Another benefit of doing this is that it's possible to get more locality from allocations by allocating all the space for variable length members of a struct
in one allocation rather than allocating them separately (avoids multiple allocation call overheads and gives you some cache locality rather than bouncing all over memory).