I'm learning about VLAs and wrote the following example:
struct array_t{
const size_t length;
const char data[];
};
struct array_t *create(const size_t n, const char data[n]){
const size_t data_offset = offsetof(struct array_t, data);
struct array_t *array = malloc(data_offset + n * sizeof(char));
memcpy(&(array -> length), &n, sizeof(n));
memcpy(&(array -> data), data, n);
return array;
}
So I tested it with
char ca[3] = {'a', 'b', 'c'};
struct array_t *array_ptr = create(5, ca);
and it compiles fine (unfortunately). As I figured out 6.7.6.2(p5):
If the size is an expression that is not an integer constant expression: if it occurs in a declaration at function prototype scope, it is treated as if it were replaced by *; otherwise, each time it is evaluated it shall have a value greater than zero.
So obviously n is not a constant expression and const char data[n] is simply treated as const char* which is not what I wanted.
So is there any reason of such arrays declarations if they don't give any type safety? Maybe we can write some macro function that will do the following:
#define create_array_t //...
const char a1[5];
const char a2[10];
const char *a_ptr;
create_array_t(5, a1); //fine
create_array_t(5, a2); //error
create_array_t(5, a_ptr); //error
create(5, ca);, wherecais ofchar [3], aren't you breaking the contract?data_offset.sizeof(array_t)gives the correct result, alignment for the FAM and all.data_offset