2

I am rewriting some old code which has an array of structs, each with an array member whose length is fixed at compile-time. The number of structs in the outer array is determined at compile-time to fit in a (typical) memory page. I would like to make the inner array variable at runtime, but keep the “outer array fits in a page” logic intact (and use sysconf(_SC_PAGESIZE) to get the page size precisely). So my structs have a flexible array member

struct foo_t 
{
  bar_t *bar;
  float baz[];
};

I would like an array of these things, but of course that is not allowed. But all of these structs will have the flexible array member the same size (run-time determined), so can I have an “array” of them instead? That is, have a char * with enough space to fit n of them, do the offset calculations myself, and cast the pointer offsets to foo_t * and then access, modify, etc.

My target is C99, C11 at a push.

6
  • 3
    Use an array of pointers to the structure instead. Commented Dec 21, 2019 at 11:21
  • Some-programmer-dude: the point is that I want the structures themselves in the same page (there is a lot of inter-struct calculation involved) Commented Dec 21, 2019 at 11:29
  • 1
    Then you need to do your memory management manually. Perhaps one page for the actual structures and their data, then you can have an array of pointers into the page? Just don't forget alignment issues. Commented Dec 21, 2019 at 11:33
  • are you going to change the struct size runtime? (i mean toi resize it?) Commented Dec 21, 2019 at 12:13
  • The size of the structures means that it should be feasible to have the pointers in the same page, having an outer struct with its own variable-length member to hold them. That sounds worth a test implementation, I'll give it a look. But my guts tell me that having these pointers is really just exchanging pointer arithmetic for pointer dereferences, the latter boing more expensive, contrary to my "boy racer" nature :-) Commented Dec 21, 2019 at 12:16

1 Answer 1

4

The C standard does not support this. In practice, you can calculate the run-time structure size and element positions:

#include <stddef.h>


typedef struct Unknown bar_t;


struct foo_t
{
    bar_t *bar;
    float baz[];
};


/*  Calculate the size required for an array of struct foo_t objects in which
    each flexible array member has NElements elements.
*/
size_t SizeOfFoo(size_t NElements)
{
    /*  Create an unused pointer to provide type information, notably the size
        of the member type of the flexible array.
    */
    struct foo_t *p;

    /*  Calculate the size of a struct foo_t plus NElements elements of baz,
        without padding after the array.
    */
    size_t s = offsetof(struct foo_t, baz) + NElements * sizeof p->baz[0];

    //  Calculate the size with padding.
    s = ((s-1) / _Alignof(struct foo_t) + 1) * _Alignof(struct foo_t);

    return s;
}


/*  Calculate the address of the element with index Index in an “array” built
    of struct foo_t objects in which each flexible array member has NElements
    elements.
*/
struct foo_t *SubscriptFoo(void *Base, size_t NElements, ptrdiff_t Index)
{
    return (struct foo_t *) ((char *) Base + Index * SizeOfFoo(NElements));
}

There may be some language-lawyer problems with this, but I do not expect them to affect practical compilers.

Sign up to request clarification or add additional context in comments.

2 Comments

This is just the sort of thing I meant by quoting "array", thanks for the details on the precise size calculation, I'd seen that it was in the P99 macro collection but it gets scary in there :-).
caution: strict-aliasing-rule.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.