Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to preserve stack space with good design?

I'm programming in C for RAM limited embedded microcontroller with RTOS.

I regularly break my code to short functions, but every function calling require to more stack memory. Every task needs his stack, and this is one of the significant memory consumers in the project.

Is there an alternative to keep the code well organized and readable, still preserve the memory?

like image 684
landmn Avatar asked Sep 25 '08 19:09

landmn


3 Answers

Try to make the call stack flatter, so instead of a() calling b() which calls c() which calls d(), have a() call b(), c(), and d() itself.

If a function is only referenced once, mark it inline (assuming your compiler supports this).

like image 117
John Millikin Avatar answered Oct 12 '22 13:10

John Millikin


There are 3 components to your stack usage:

  • Function Call return addresses
  • Function Call parameters
  • automatic(local) variables

The key to minimizing your stack usage is to minimize parameter passing and automatic variables. The space consumption of the actual function call itself is rather minimal.

Parameters

One way to address the parameter issue is to pass a structure (via pointer) instead of a large number of parameters.


foo(int a, int b, int c, int d)
{
...
   bar(int a, int b);
}

do this instead:


struct my_params {
   int a;
   int b;
   int c;
   int d;
};
foo(struct my_params* p)
{
   ...
   bar(p);
};

This strategy is good if you pass down a lot of parameters. If the parameters are all different, then it might not work well for you. You would end up with a large structure being passed around that contains many different parameters.

Automatic Variables (locals)

This tend to be the biggest consumer of stack space.

  • Arrays are the killer. Don't define arrays in your local functions!
  • Minimize the number of local variables.
  • Use the smallest type necessary.
  • If re-entrancy is not an issue, you can use module static variables.

Keep in mind that if you're simply moving all your local variables from local scope to module scope, you have NOT saved any space. You traded stack space for data segment space.

Some RTOS support thread local storage, which allocates "global" storage on a per-thread basis. This might allow you to have multiple independent global variables on a per task basis, but this will make your code not as straightforward.

like image 20
Benoit Avatar answered Oct 12 '22 13:10

Benoit


In the event you can spare a lot of main memory but have only a small shred of stack, I suggest evaluating static allocations.

In C, all variables declared inside a function are "automatically managed" which means they're allocated on the stack.

Qualifying the declarations as "static" stores them in main memory instead of on the stack. They basically behave like global variables but still allow you to avoid the bad habits that come with overusing globals. You can make a good case for declaring large, long-lived buffers/variables as static to reduce pressure on the stack.

Beware that this doesn't work well/at all if your application is multithreaded or if you use recursion.

like image 43
mbac32768 Avatar answered Oct 12 '22 11:10

mbac32768