11

These are two ways I can hold a variable outside of loop (or any function).

First, I can declare it with global scope outside of loop:

void setup()
{
    Serial.begin(9600);
}

int count = 0;

void loop()
{
    Serial.println(count);
    count++;

    delay(250);
}

I can also declare it static inside the loop:

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    static int count = 0;

    Serial.println(count);
    count++;

    delay(250);
}

What difference, if any, will this make?

Cybergibbons
  • 5,420
  • 7
  • 34
  • 51

3 Answers3

10

The most basic difference is of scope.

In the first case, you are declaring a global variable. It is a variable that is accessible in every scope after its definition.

void setup()
{
    Serial.begin(9600);
}

void inc();
int count = 0;

void loop()
{
    Serial.println(count);
    count++;

    inc();

    delay(500);
}

void inc() //Can edit the value of count
{
  count=count+1;
};

In the second case, you are declaring a static variable with local scope. The variable will persist for the entire program run similar to global variables, but will be accessible only in the code block it is declared in. This is the same example, with only one change. count is now declared as a static variable inside loop.

void inc();

void loop()
{
    static int count = 0;
    Serial.println(count);
    count++;

    inc();

    delay(500);
}

This will not compile as the function inc() does not have access to count.

Global variables, however seemingly useful, come with some pitfalls. These can even cause damage when it comes to writing programs that can interact with the physical surroundings. This a very basic example of something that is quite likely to happen, as soon as programs start getting larger. A function may inadvertently change the state of a global variable.

void setup()
{
    Serial.begin(9600);
}
void another_function();
int state=0;

void loop()
{
    //Keep toggling the state
    Serial.println(state);
    delay(250);
    state=state?0:1;

    //Some unrelated function call
    another_function();
}

void another_function()
{
  //Inadvertently changes state
  state=1;

}

Such cases are very hard to debug. This type of problem however, can easily be detected, by simply using a static variable.

void setup()
{
    Serial.begin(9600);
}
void another_function();

void loop()
{
    static int state=0;

    //Keep toggling the state
    Serial.println(state);
    delay(250);
    state=state?0:1;

    //Some unrelated function call
    another_function();
}

void another_function()
{
  //Results in a compile time error. Saves time.
  state=1;

}
asheeshr
  • 3,847
  • 3
  • 26
  • 61
5

From a functional perspective, both versions generate the same result, since in both cases the value of count is stored between the executions of the loop() (either because it is a global variable or because it is marked as static and therefore keeps its value).

So the decision which to choose come down to following arguments:

  1. Generally, in computer science, it is encouraged to keep your variables as local as possible in terms of scope. This usually results in much clearer code with less side-effects and reduces chances of someone else using that global variable screwing up your logic. E.g. in your first example, other logic areas might change the count value, whereas in the second, only that particular function loop() can do so.
  2. Global and static variables always occupy memory, where as locals only do when they are in scope. In your above examples that makes no difference (since in one you use a global, in the other a static variable), but in bigger and more complex programs it might and you could save memory using non-static locals. However: If you have a variable in a logic area that is executed very often, consider making it either static or global, since otherwise you loose a tiny bit of performance each time that logic area is entered, since it takes a bit of time to allocate the memory for that new variable instance. You need to find a balance between memory load and performance.
  3. Other points such as better layout for static analysis or optimization by the compiler might also come into play.
  4. In some special scenarios, there might be issues with the unpredictable initialization order of static elements (not sure about that point, compare this link though).

Source: Similar thread on arduino.cc

Philip Allgaier
  • 245
  • 3
  • 13
2

Both variables are static - they persist for the entire execution session. The global is visible to any function if it declares - not defines - the global, or if the function follows the definition in the same compilation unit (file + includes).

Moving the definition of count to inside of a function both limits its scope of visibility to the nearest enclosing set of {}es, and gives it function invocation lifetime (it is created and destroyed as the function is entered and exited). Declaring it static as well gives it execution session lifetime it exists from the start to the end of the execution session, persisting across function invocations.

BTW: be cautious about using initialized statics within a function, as I have seen some versions of the gnu compiler get this wrong. An automatic variable with an initializer should be created and initialized on every function entry. A static with an initializer should only be initialized once, during the execution setup, before main() is given control (just as a global would be). I have had local statics get reinitialized on each function entry as though they were automatics, which is incorrect. Test your own compiler to be sure.

JRobert
  • 15,407
  • 3
  • 24
  • 51