3

I have records with flexible array member

typedef struct record {
    unsigned foo;
    signed bar;
    double number[];
} record;

I have multiple records with the same amount of numbers so I can arrange them in array. I would like to allocate them into one continuous memory space.

const unsigned numbers = ...;
const unsigned records = ...;
const size_t record_size = sizeof(record) + numbers*sizeof(double);
record *prec = malloc(records*record_size);

So now I know record_size and I can access it but what is best practice how to do it correctly and safely by given record index?

I can do it when I would separate header containing foo and bar and numbers, but I would like to keep record together for cache coherency.

Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
  • The standard says: _A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array._ You're trying to make an array of structures with FAM — that does not work. You can have an array of pointers. – Jonathan Leffler Jan 16 '16 at 01:26

1 Answers1

1

Since only you know the actual layout, the C compiler can't help you. Thus, you must do the address-calculation yourself. It will require some casts to do the pointer-arithmetic at byte level:

record * get_record(record *base, size_t numbers, size_t index)
{
  return (record *) ((unsigned char *) base +
                    index * (sizeof *base + numbers * sizeof *base->number));
}

Given the above (and your code); you can access the array like so:

record *first = get_record(base, numbers, 0);
first->foo = 4711;
record *second = get_record(base, numbers, 1);
second->foo = 17;

One obvious drawback is that you're going to have to keep the numbers value around. This can be improved by modelling the entire array with an explicit "base" structure, that holds the size of each element and the base pointer. Of course it can be co-allocated with the elements themselves to keep it all together and reduce the distances of the involved pointers.

Also, please don't cast the return value of malloc() in C.

Community
  • 1
  • 1
unwind
  • 391,730
  • 64
  • 469
  • 606