0

The C code is supposed to run on an embedded system, something like Arm CortexM or similar.

Two API interface designs are possible:

typedef struct { vars } t_object;
void init(t_object* p_object);
void run(t_object* p_object);

t_object my_object;
init( &my_object );
while(1)
    run( &my_object ); 

or

typedef struct { vars } t_object;
t_object* init( );
void run(t_object* p_object);
void deinit(t_object* p_object);

t_object* p_my_object;
p_my_object = init( );
while(1)
    run( p_my_object );

In the first case object is statically allocated on stack, and in the second case init() dynamically allocates the object on heap.

What are the reasons to prefer one of the two ways in designing the interface?

Danijel
  • 8,198
  • 18
  • 69
  • 133
  • 1
    That purely depends on the environment where the program runs. Both the approaches have its own pros and cons depends on the platform. – kiran Biradar Oct 14 '19 at 10:10
  • Generally making the _caller_ responsible of the memory management of called code is a bad idea. The caller may not be aware of that responsibility, which will result in a memory leak If you do this, some naming convention to make it obvious such as `allocate_object`, `delete_object` functions might be in order. – Clifford Oct 14 '19 at 10:24
  • @Clifford Have in mind that there will ever be only one instance of this object, and that it will "run forever". The `deinit()` is provided, but will consequnetly never be used here. – Danijel Oct 14 '19 at 10:28
  • 1
    This isn't really opinon-based. There is an existing industry de facto standard, opaque type. The only reason why one wouldn't use it is because one doesn't know about it. – Lundin Oct 14 '19 at 11:02
  • @Danijel In which case, dynamic allocation serves no purpose, the init() function might simply return a pointer to a static object. That then requires you to call the init function to get a reference to the object - thus guaranteeing that it will be initialised before use. Note the fact that this is a singleton is not mentioned in your question. It is relevant, so should be mentioned. – Clifford Oct 14 '19 at 11:55

2 Answers2

4

Go with the first one.

By giving user the responsibility to create object, he has can use static, automatic or dynamic depending on what is needed. It's possible to use different allocation scheme for actual usage and unit test usage.

If you are on embedded freestanding system where memory is calculated in kilobytes, rather than megabytes, then dynamic memory allocation is usually a luxury you don't need. Usually static storage is better for "eternal" objects, and stack for temporary objects.

user694733
  • 15,208
  • 2
  • 42
  • 68
4

You should look at the concept known as "opaque type" or "opaque pointers". It is a design pattern in C which allows you to use private encapsulation by utilizing forward declaration of the struct. In order for that to work, your functions must be using pointers and allocation must be done inside your code.

In low-end embedded systems, dynamic allocation should never be used. Allocation of opaque types is done with static memory pools. See Static allocation of opaque data types.

Code example of how to implement a static memory pool: https://stackoverflow.com/a/54999410/584518

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    I am not sure there is a consensus about this? – Danijel Oct 14 '19 at 14:38
  • Not sure what you are referring to as "this", but strongly avoiding dynamic allocation of memory in embedded systems is the norm. The is no compelling need and the downside consequences are just too great. – andy mango Oct 14 '19 at 15:07
  • @Danijel Regarding opaque type it is even recommended by MISRA-C nowadays (directive 4.8), so it's even part of industry standards. However, out of rotten tradition, many C programmers tend to lack experience of proper program design and design patterns. Some read K&R too much, others came to C from assembly, others are stubborn old-timers who reject OO and so on. – Lundin Oct 15 '19 at 06:52
  • I am clear about dynamic allocation. What I ment by "consensus" was about using `alloca()` in the link above. I am not clear whether this can be done without `alloca()` or not. – Danijel Oct 15 '19 at 12:04
  • @Danijel Typically you just create your own memory pool as a fixed size array, then have the constructor allocate 1 object from this. Means you get an upper limit to how many objects there will be, but embedded systems should be deterministic. – Lundin Oct 15 '19 at 12:06
  • @Lundin A quick and dirty pseudo-code maybe (added to answer above)? – Danijel Oct 15 '19 at 12:08