Using the static keyword in C

There are many topics in the C language that often confuse developers but the use of the static keyword seems to be one of the more common.  One of the points of confusion is how static affects variables that are local and variables that are global.  In each instance the static keyword has a different effect on where the data is stored and how it persists throughout the life of the program.  There are three primary uses for the static keyword; local variable in a function, global variable in a module and a function in a module.  In this post we will examine all three uses and how they affect not only where variables are stored but also the use of static can increase code quality.

In general, static is a storage class specifier that can be applied to any data type.  While static has many definitions, the definition that best applies to all three uses is that static tells the compiler to make the variable or function limited in scope while allowing it to persist throughout the life of the program.  This allows static to be used to encapsulate or hide variables from the rest of the program to prevent inadvertent access. The developer is then able to strictly control how variables are accessed within a module which is considered good programming practice.

When a variable is declared within a function without the use of static, the variable is considered to be an automatic variable.  Automatic variables are created and stored on the stack (or within a CPU register) and destroyed when the function returns.  If a developer wanted the variable within the function to retain its value between calls, the variable would be declared as static.  In this case, the variable would no longer be stored on the stack but would instead be stored in the global memory space; however, even though the variable itself is stored in global space the compiler enforces a local scope on the variable causing it to only be visible within that function!  Other functions within the module will be unaware that the variable exists.  Not only will the variable retain its value throughout the life of the program, the static variable will also only be initialized the first time the function is called.

Defining a variable within the global scope of a module (outside of any function) implicitly declares the variable as extern.  This causes the variable to be defined within the global memory space and for the linker to link other extern definitions to it. If the variable is only going to be used within the current module then it should be explicitly declared with static. Good programming practice indicates that a variable should be declared within the most local, applicable scope.  Therefore, if the variable is only used within a single function then the more appropriate location to declare the variable may be within the function itself rather than the module scope.  Static variables declared at the module level are initialized only once during the C copy down that occurs when the processor is being initialized.

Static can also be applied to a function within a module.  By default, functions are implicitly declared as extern. This means that if a function is defined within a c file and not prototyped within a header file, the compiler will still be able to link to the function (with perhaps a few warnings to the developer).  In order to only make a function usable within a single module, the developer can place the static keyword before the function declaration.  This will effectively hide the function from the external world and protect the use of that function and its variables.

The use of the static keyword has many uses.  Its most effective use is to limit the scope of variables defined within a module or function.  Through the use of static, variables and functions can be hidden from the external program, resulting in behavior that is similar to the use of private and public in more modern object oriented languages.

  • Told you it takes me a couple of times...

    One distinction is a const pointer to an array.this means the pointer cannot be changed, However, the contents of the array may be changed.

  • > const declares thing is constant and not to be changed.

    Depending on how you read this, it could be misleading. "const" does mean that the declaration can't be used to change the data, but it does not ensure that the data won't change (so, somewhat unfortunately, it does not really mean "constant"). "const" means "read-only" for the program.

    Here is a fun example that helped me to understand the meaning of both const and volatile: Supposing that your memory-mapped hardware register is read-only, a pointer to it might sensibly be declared as "const volatile unsigned *p;". Trying to write through p would give a compilation error, but the compiler should safely emit a read every time it is asked to because "volatile" tells it that the memory contents might have changed since the last read. So it is const but not constant.

  • To be honest, I always need to look up the usage on this, ie

    const char const *foo;

    char const *foo;

    const char *foo;

    are all different. The way I figure it out is the thing to the right of const is the const thing.

    Sorry, no.  These are all the same.  The order of char and const does not matter, only the position relative to the star:

    const char * const foo; // constant pointer to constant data

    const char * foo; // pointer to constant data

    char * const foo; // constant pointer to data

  • Keep in mind there are two data areas - initialized ("int foo = 5;") and BSS ("int bar;")

    I don't have the time this instant to dig it up, but the C standard specifies BSS is inited to 0 before main() is called.

    volatile means the variable may change, and the compiler must NOT assume it will stay the same value - this is applied at optimization. For example, if the value is a hardware status register memory-mapped into the address space, the value can change as the device operates. The volatile keyword was added because of C in embedded systems.

    volatile uint8_t  *stat_reg = 0x1234;  // Create a pointer to the status reg, address 0x1234

    uint8_t stat;                                    // create a variable

    stat = *stat_reg;  // read the status register

    while( *stat_reg & STAT_BUSY ) /*WAIT*/  ;    // wait until the device is not busy - the status can change

    const declares thing is constant and not to be changed. this can be a pointer, or the thing pointed to. To be honest, I always need to look up the usage on this, ie

    const char const *foo;

    char const *foo;

    cost char *foo;

    are all different. The way I figure it out is the thing to the right of const is the const thing. BUT - even though I have been using C for 30+ years, this one takes me a couple of stabs to get it right. The compiler will complain if you get it wrong.

    In embedded systems, this lets you control where the values are stored - in RAM or FLASH (EEPROM). NOTE: every embedded system (MPU family) is slightly different!

    int foo = 5;  // copied from FLASH to RAM before main()

    const int bar = 6; // store the 6 in FLASH and bar has a flash address.

    the "int foo = 5;" case is interesting. The 5 is stored in FLASH, then on boot, copied to RAM at address 'foo". You can change the RAM value as you wish. BUT, on reboot, the FLASH copy is not changed so foo = 5 again.

  • Thanks for the feedback.  I also want to thank Peter Wilson who pointed this out.  I've made a minor update to correct.