My question is related to this one : c define arrays in struct with different sizes
However, I do NOT want to use dynamic allocation (embedded target).
- Problem recap :
In C, I want to have two versions of the same structure, each one with a different size for its static arrays. Both the structures will be used by the same functions through pointer parameter.
typedef struct {
short isLarge; //set 0 at initialization
short array[SIZE_A];
//more arrays
} doc_t;
typedef struct {
short isLarge; //set 1 at initialization
short array[SIZE_B];
//more arrays
} doc_large_t;
void function( doc_t* document ) {
if ( document->isLarge ) {
//change document into doc_large_t* [1]
}
//common code for both doc_t and doc_large_t
}
- Questions :
(1) The above description needs a way to dynamically cast the pointer doc_t* pointer to doc_large_t* document [1]. Is that possible ? How ?
(2) An other solution i came with is to have a common header data part for both structure, including not only the isLarge flag, but also the pointers to the following static arrays. How ugly is that ?
(3) Also, do you have a good trick or workarround I could use ?
EDIT :
- More context :
My application is a path finding on an embedded MCU.
I have geometrical objects, like polygons. Polygons can describe simple rectangular obstacles, as well as more complex shapes (such as the accessible area).
Complex polygons can have a huge amount of vertices, but are in small quantity. Simple polygons are very common.
Both will use the same algorithms. I know in advance which polygon will need more vertices.
What I am trying to do is to optimize working memory to make it fit into the MCU. (i.e. small shapes get small arrays; complex ones get large arrays)
Create the arrays globally and use a pointer pointig to the big or small array.
It's easy with
malloc()
or similar dynamic allocation methods. Just use a flexible array member:To allocate a "small structure":
To allocate a "large structure":
Note that you must keep the
largeArray
element last, which means that thearray
element must be next-to-last for this to work.Depending on how you do your own allocation, this may or may not be applicable.
(It's also a bit of a hack, since it depends on being able to access data in
largeArray
by using an index ofSIZE_A
or greater onarray
. That's accessing an object outside its bounds...)After the edit, I think the best thing you can do is to profile your needs defining max simple and complex polygons your target can manage and then declare a pool of simplex and common polygons, like:
This is a simple implementation designed for a static "instantiation" of structs. You can also enhance the code with a create/destroy function that trace which array into pool is free to be used.
Your number 2 solution is the right idea. It's unclear to me why you think that is ugly. Maybe this beautiful implementation will change your mind.
You can implement single inheritance is C by placing the base structure as the first member of the inheriting structure. Then inheriting objects can be referenced with a pointer to the base type.
The
array_ptr
member indoc_base_t
isn't necessary for the inheritance mechanism. But I added that specifically for the "common code" portion of your function. Ifdoc_base_t
didn't include thearray_ptr
then you could cast the genericdocument
to either adoc_small_t
ordoc_large_t
type based upon thebase_type
value. But then you might need a different implementation for each inherited type. By adding thearray_ptr
member todoc_base_t
I suspect you could write a common implementation for all inherited types.So you will statically declare all your instances of
doc_small_t
anddoc_large_t
. And you'll initialize both thebase.doc_type
andbase.array_ptr
members when initializing each object. Then you will cast both types of objects to doc_base_t before callingfunction
. (Or pass the address of thebase
member, which results in the same pointer value.)Updated example:
You should try to keep a single structure and for the different array sizes put them in an
union
. I don't know whether the following structure would make sense to your case.If
isLarge
is0
, set the value forarray_A
array and if1
set the value for arrayarray_B
.Idea similar to what you mentioned in your question already (pointers to arrays), but with only one single pointer:
If extraData is NULL, you have a small polygone, otherwise, you find the additional data in the struct referenced. Admitted, iterating over all values for large polygons gets a little nasty...
If you can use global arrays of predefined size for each object type (as Dominic Gibson proposed - a good proposition, by the way), you could spare the isLarge flag by replacing it with a function:
Of course, all polygons (in above case: the large ones at least) would have to live in this array to make it work. If you create at least one dynamically or otherwise elsewhere (stack, another global variable) - we are out...