I wrote a dynamic array like this:
#include <stdlib.h>
typedef struct {
size_t capacity;
size_t len;
} __dynarray_header;
void* dynarray_new() {
__dynarray_header* header = malloc(sizeof(__dynarray_header));
header->capacity = 0;
header->len = 0;
return header + 1;
}
The dynamic array can be accessed with a []
operation. When resizing, I can use __dynarray_header*)array - 1
to retrieve capacity and length information.
The idea works in small tests. However, GCC warns about breaking strict-aliasing.
I've also found some larger projects segfault without the -fno-strict-aliasing
compiler option (with -O3
optimization).
I know what strict-aliasing is, and why my code breaks strict-aliasing.
My question is: Is there a better way to implement a dynamic array supporting both the []
operation and dynamic resizing than the one I showed above?
Extra:
A demo program using this dynamic array:
int* arr = dynarray_new();
arr = dynarray_resize(sizeof(int) * 2);
arr[0] = 1;
arr[1] = 2;
arr = dynarray_resize(sizeof(int) * 4);
arr[2] = 3;
arr[3] = 4;
dynarray_free(arr);
The main optimization afforded by -fstrict-aliasing
is that references to foo *
can be arbitrarily moved past references to bar *
in most circumstances. The segfaults you see are likely due to a reference getting moved past a free
type operation somewhere.
While this feels a little dirty, you may be able to make it work under C89 by adding a union of prospective array element types into your structure, such as:
typedef struct {
size_t capacity;
size_t len;
union {
int i;
double d;
my_type mt;
etc e;
/* add additional types here. */
} array_head;
} __dynarray_header;
Then, instead of returning header + 1
, return (void *)&(header->array_head)
.
Now, even with strict aliasing, the compiler is more likely to consider a pointer to __dynarray_header
to possibly alias a pointer to anything in that union, unless the pointers are also restrict
-qualified. (I'm assuming for your use case, they are not, at least in the contexts that trigger seg-faults.)
Still... as Dennis Ritchie said, it seems like "unwarranted chumminess with the implementation." Or, in other words, a hack. Good luck!
(Edit: As Carl above reminded me, in C99 you can use flexible array members. I haven't used them, simply because C99 support doesn't seem to be the default in the C compilers I use. Here's IBM's reference: http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzarg%2Fflexible.htm )