static vs. malloc

Designer's notes #9 - Home - Prev - Next
Řyvind Teig, Trondheim, Norway (http://www.teigfam.net/oyvind/)

No handle to hold these statics

If you are an embedded programmer doing f.ex. state machine implementations in C: please, don't use variables declared as static. If you need higher speed and smaller code size: well, do it if you must.

Once I came across code containing static variables. Surprise! It wasn't one variable, there were hundreds. I will describe why this turned out to be a problem. Even if they were there by design, not coincidence. They had represented no problem on initial usage.

The static keyword defines two things in ANSI C.

Firstly, the variable (or function) has file scope only. This means that it is not possible to export any knowledge about this static object outside the file. This is nice. Also, it defines the name space of the object. So, the name may be reused (check this).

Secondly, the static keyword, for variables, means that they may be statically allocated in RAM memory. Once given an address, that address is kept, at all times.

The stack is not involved in any way with statics. The stack contains the parameters to and local variables in functions. It expands on calls and shrinks on returns. Locations are reused. It may not be so easy to see the different semantic of storage qualifiers. You could look in a function and see two local variables, one with the static keyword and one without. The one with static is at the init address space; the one without is on the stack.

Which variable will live the longest: the local static or the local stack-based non-static? As the name suggests, the static variable survives at all times. So, if you assign an initialization value (static int value=(-1);) to a static value hidden far away in a function, the init code generated by the linker will initialise the value. This happens before your program enters main.

A static variable of this sort certainly does not give the programmer much overview of what's happening (if this is needed). However, you were only assumed to use what the other guy programmed, and should not care that it contains loads of statics. But, should you indeed need to understand, then there would have been an alternative solution. I'll come to that shortly.

Use of hidden statics certainly works for applications running in big operating systems, like Mac OS X or Windows. These operating systems are able to load a binary file. This means that every address allocation is local. So, if you have a static in a program called TuringMachine, the operating system could assign that static to the storage address 0x100000 (0x=hex). If you start TuringMachine a second time, the operating system could assign the same named static into address 0x2000000. The operating system gives each instance of the program an individual section of its heap with a call to the operating system's malloc function.

Observe that when a function contains local static variables, it's not necessary with many parameters to functions. They keep their own state in permanent storage. This is reminescent of one of the traits of object-oriented programming or process-oriented programming. It's good.

However, an object built with static is like a house on a hundred poles - it's hard to lift from the ground. Should one want to create a one new instance of this sort of object - that's when the problems start. Create two variables of each, two functions of each, all suffixed my "_1" and "_2"? Complex, not much scalable and reluctant to errors.

Instead, make a single struct containing all variables, have some callee on the outside malloc the data space for it, or do it inside an init function. Then, parameterize all functions with a pointer to this single struct. This is much more portable.

However, there is a price. This dynamic memory allocation (malloc) incurs an extra indirection every time a variable inside the struct needs to be accessed (the -> operator in C). A good compiler will probably keep values in registers as long as possible, or keep resolved addresses locally.

But, if there is a chance your internal object is going to be so popular that somebody may want it, do consider the malloc'ed solution. And should it later be used inside a small real-time operating system that does not have loading of binary files or objects (where all has to be statically linked into a single burn before the op-sys starts), then absolutely consider dynamic memory handling. In most small embedded systems you would only need to malloc, and never remove or free them. If so there would not be any memory fragmentation with holes of non-used segments.

So, every time you use static, learn to see the blinking yellow light.

(Updated 31 March '09)

Other publications at http://www.teigfam.net/oyvind/pub/pub.html