Global vs Local variables and efficiency

I was wondering what the difference is in practical terms between using local and global variables in subroutines.

Consider the following code:

void setup()
{
}

void loop()
{
  int i = 0;
  boolean contactedOK;
  while(!contactedOK || i < 3)
  {
    contactedOK = RadioDataToBase()
    i++
  }
  if(i > 2) SignalError()
}

and then the following code:

int i = 0;
boolean contactedOK;

void setup()
{
}

void loop()
{  
  while(!contactedOK || i < 3)
  {
    contactedOK = RadioDataToBase()
    i++
  }
  if(i > 2) SignalError()
}

The first block creates and (I assume) destroys the variables for each iteration of the loop where as the second code block does not. It only creates them once and reuses them.

While I appreciate that the first block of code has better form, does it:

  • take longer to execute because of all the creating and destroying of variables?
  • create a problem with memory fragmentation and may lead to memory holes?

i.e. might the second block, although poorly written, be easier on the processor and lead to fewer issues/hangs?

  • take longer to execute because of all the creating and destroying of variables?

The first several local variables are assigned to registers. The cost is zero.

If the compiler can't fit all locals into registers it then creates a "stack frame". There is a slight performance hit for locals residing in a stack frame.

  • create a problem with memory fragmentation and may lead to memory holes?

Nope. Not a problem.

i.e. might the second block, although poorly written, be easier on the processor and lead to fewer issues/hangs?

The second block is more likely to lead to problems for the simple reason that global variables often lead to unexpected side-effects.

I would like learn more about this. Few days back I had a long talk with my friend who has long history with C programming. I asked about just the same question from him, and also about volatile variables. I thought I almost had it, but what kind of problems there can be?

Our program has (too) many global variables that are used by so many subroutines. Sometimes some calculations gives unexpected results, but most of them were because I mixed INTs and DOUBLEs the wrong way, now I know how to handle them together.

Last 25 years I've programmed with good old QB and VB6, and that doesn't have problems with memory capasity, situation is completely different now, and new (C) language to me as well. So many places to go wrong...

Cheers,
Kari

Last 25 years I've programmed with good old QB and VB6, and that doesn't have problems with memory capasity, situation is completely different now, and new (C) language to me as well

Actually, the PC you were programming on didn't have memory capacity issues, not the language. Now you are working in an environment that doesn't have sophisticated memory management and it only has a few K of RAM. The programming language you are using is irrelevant compared to the differences in hardware between a PC and 8-bit microcontroller.

:stuck_out_tongue:
Well, you can put it that way, it's ok. My programs have been relatively small so far, when it comes to memory usage. Anyway, I've never needed to worried about that.

Now the situation is completely different, and it may cost me if I don't learn to be smart with my code. I have Mega for the final "product", but coding carefully with Duemilanove avoid me to waste precious bytes. I don't know yet how to calculate total use of variable space, but I believe it will tell me when I have gone too far.

Kari

I don't know yet how to calculate total use of variable space, but I believe it will tell me when I have gone too far.

No, "it" (whatever "it" is) won't. There is a tool that can estimate what the SRAM usage is but it does not take into account what gets allocated during runtime. For example, say you recursively call a subroutine that defines a variable. Each iteration must allocate space for that variable. Neither the complier or any other tool will know how to calculate how many times that subroutine is called and how much space will be consumed.

The only real indication you've run out of memory is when the ATmega328 suddenly goes off into the weeds. Welcome to the world of microcontrollers. :wink:

I don't know yet how to calculate total use of variable space, but I believe it will tell me when I have gone too far.

I don't know what "it" is that you think is going to tell you that, but it won't be the compiler.

Thank you guys, I really needed that information.

I don't use many local variables, that's why I thought that compiler might be aware that sram would be full, and hopefully let me know.

Long way for me to really understand the deepest secrets of mc's. So far the program logic have been the only thing to worried about, now there's memory and timing too. And many things I'm not aware of yet.
:~

Cheers,
Kari

Quite the contrary in this case. In fact, the second example (the one with the global) is the only
one that is going to work properly.

The reason being is that there is a difference in how locally declared variables are handled vs how
global variables are handled.
ALL global variables are zeroed out by the C startup code prior to your code being called. Local variables are not.
When a local variable is declared, space is allocated for it, but it is not zeroed. So while the initial contents
of a global is always zero, the initial contents of a local that is not explicitly initialized
is undefined and cannot be assumed to be anything.

So in the example using the global contactedOK, its initial value in loop() will be 0 (because the
startup code zeroed it), in the example where it is a local, its initial value is undefined and could be anything.
This looks like it will be an issue if contactedOK is not initially 0.

Also in the global example:
The assignment of 0 to i is unneeded and in fact the declaration may cause the compiler to waste 2 bytes of flash to
store that 0. (I haven't looked to see if the compiler is smart enough to ignore this assignment)
By explicitly assigning an initial value for a variable(0 in this case), the compiler and startup code
must ensure that the desired initial value is set,
so rather than letting the startup up code clear the variable to 0, the startup code must
fill in the value of the variable with the desired initial value (which also happens to be 0 in this case).

The reason I say may, is I've not looked to see if gcc is smart enough to ignore an explicit assignment of 0
to a global and let the start up code clear it instead. It might be smart enough to do this.

--- bill

BTW, I needed to read something again, and this seems to have something wrong? Maybe it is the fact that I can't read between the lines too well. What was the point?

Cheers,
Kari