Lesson #16

Duration. Static vs Automatic. Rules for Initialization.

Overview

In this lesson I will cover the following topics

  1. The definition of "duration".

  2. The difference between static and automatic duration.

  3. How you can use local static variables.

Body

What is "duration"?

Each variable that you create in your program has a certain lifetime. That lifetime is its duration. There are three types of duration that variables in C programs can have: static, automatic, and dynamic. We don't need to concern ourselves with dynamic duration in this course. That is a topic for a second course. However, you do need to understand the difference between static and automatic duration.

Static

Variables with static duration exist the entire time the program is running. They take their initial values, if any, just before the program starts. If they are not explicitly initialized they will be given the initial value of zero. If they are explicitly initialized they can only be initialized with constants.

Automatic

Variables with automatic duration exist only while the block in which they are declared is running. The are created fresh each time that block is entered, and destroyed when the block exits. If they are not explicitly initialized, their initial values will be unknown. If they are explicitly initialized, their initial values are calculated fresh each time they are created. Their initial values can be any expression involving other variables that are in scope at the time.

Whew! So what does all that mean? First you need to know that all global variables have static duration. No exceptions. Local variables have automatic duration unless they are said to be static. Here are some examples to illustrate.

#include <stdio.h>

// Static duration. No explicit initializer. Initialized to zero.
int i;

// Static duration. Explicitly initialized to 10.
int j = 10;

// Static duration. Error! Can't initialize using an expression.
int k = 2 * j + 1;

int main(void)
{
  // Automatic duration. No explicit initializer. Initialized to an
  // unknown value.
  int i;

  // Automatic duration. Initialized each time this block is entered.
  int j = 10;

  // Automatic duration. Fine. Can be initialized with any expression.
  int k = 2 * j + 1;

  return 0;
}

There are a few important points to keep in mind about this.

Automatic (local) variables get unknown values initially if you don't explicitly initialize them. Often this is fine because in many cases you assign a value to the variable before you try to use it. However, just be sure you don't try to use an unknown value in your calculations! Many compilers try to detect this and issue a warning if they see you doing it.

Automatic variables can be initialized with any expression. The value of the initializer is calculated freshly each time the variable is initialized (when its block is entered).

Static (global) variables can only be initialized by constants. If you don't initialize them they are definitely initialized to zero. The initialization of a static variable occurs, in concept, just before main starts running.

Local static duration variables.

Since globals have static duration and locals normally have automatic duration it seems like you might want to use an occasional global variable because of its longer lifetime. In fact, that is not necessary. You can declare a local variable to have static duration. Here is how

int next_value(void)
{
  static int number = 0;

  number++;
  return number;
}

The variable number is an integer that is local to the next_value function. However, because its declaration starts with the word static the compiler understands that you want this local variable to have static duration. All the normal rules for static variables apply. It lasts as long as the program runs; it can only be initialized with a constant (or it will default to zero); it gets initialized just before main starts.

The key point here is that the value of number in my example above is retained between calls to the function. The first time next_value is called it increments number from its initial value of zero to one. The next time next_value is called, it increments the one to a two. The initialization only applies for the first time. In contrast, look at what happens if we make number an automatic variable

int next_value(void)
{
  int number = 0

  number++;
  return number;
}

Each and every time next_value is called, number will be initialized to zero. Thus next_value keeps returning 1 over and over again. The version with the static local variable returns the sequence 1, 2, 3, etc as it gets called again and again. The static local variable allows the function to "remember" information about the last time it was called. This is a very nice feature at times.

Actually static local variables cause problems in sophisticated programs that have multiple threads of execution. In fact, static duration data in general is tricky to handle in such programs, creating yet another reason to avoid global variables.

Some functions in the C standard library use static duration data. For example, the rand function declared in stdlib.h returns a random number between 0 and some maximum integer. In most implementations it works by computing the next random number from the last one using a formula designed for the purpose. This doesn't really return a truely random number but if the formula is a good one the sequence of numbers returned will pass a significant number of statistical tests for randomness.

How does rand remember the last random number it computed? It does so by using static duration data to hold the last value computed. The library srand function (also declared in stdlib.h allows you to set this value so that you can generate a different sequence of random numbers. Since both srand and rand share this static duration data, it's a safe bet that it is implemented as a global variable in the standard library.

Summary

  1. A variable's "duration" describes it's lifetime. Variables with static duration exist the entire time the program is running. Variables with automatic duration only exist while the block in which they are declared is running.

  2. Static duration variables get initialized to zero by default. If you explicitly initialize them you have to use constants. The initialization is done, in concept, just before the program starts running. Automatic duration variables have random values by default. If you explicitly initialize them you can use any valid expression to compute their initial values. The initialzation is done each time the block in which they are declared is entered.

  3. Although global variables are always static and local variables are usual automatic, it is possible to declare a static local variable. Such variables retain their values even after the block in which they are declared exits. Using a static local variable, you can write a function that "remembers" things about the times it executed in the past.

© Copyright 2003 by Peter C. Chapin.
Last Revised: July 15, 2003