When allocating memory for a variable sized array, I often do something like this:
struct array {
long length;
int *mem;
};
struct array *alloc_array( long length)
{
struct array *arr = malloc( sizeof(struct array) + sizeof(int)*length);
arr->length = length;
arr->mem = (int *)(arr + 1); /* dubious pointer manipulation */
return arr;
}
I then use the arrray like this:
int main()
{
struct array *arr = alloc_array( 10);
for( int i = 0; i < 10; i++)
arr->mem[i] = i;
/* do something more meaningful */
free( arr);
return 0;
}
This works and compiles without warnings. Recently however, I read about strict aliasing. To my understanding, the code above is legal with regard to strict aliasing, because the memory being accessed through the int *
is not the memory being accessed through the struct array *
. Does the code in fact break strict aliasing rules? If so, how can it be modified not to break them?
I am aware that I could allocate the struct and array separately, but then I would need to free them separately too, presumably in some sort of free_array
function. That would mean that I have to know the type of the memory I am freeing when I free it, which would complicate code. It would also likely be slower. That is not what I am looking for.
The proper way to declare a flexible array member in a struct is as follows:
struct array {
long length;
int mem[];
};
Then you can allocate the space as before without having to assign anything to mem
:
struct array *alloc_array( long length)
{
struct array *arr = malloc( sizeof(struct array) + sizeof(int)*length);
arr->length = length;
return arr;
}
Modern C officially supports flexible array members. So you can define your structure as follows:
struct array {
long length;
int mem[];
};
And allocate it as you do now, without the added hassle of dubious pointer manipulation. It will work out of the box, all the access will be properly aligned and you won't have to worry about dark corners of the language. Though, naturally, it's only viable if you have a single such member you need to allocate.
As for what you have now, since allocated storage doesn't have a declared type (it's a blank slate), you aren't breaking strict aliasing, since you haven't given that memory an effective type. The only issue is with possible mess-up of alignment. Though that's unlikely with the types in your structure.
I believe the code as written does violate strict aliasing rules, when standard read in the strictest sense.
You are accessing an object of type int
through a pointer to unrelated type array
. I believe, that an easy way out would be to use starting address of the struct, and than convert it char*, and perform a pointer arithmetic on it. Example:
void* alloc = malloc(...);
array = alloc;
int* p_int = (char*)alloc + sizeof(array);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With