Where to put variables

Hi all,

Simple question. In a C program (Arduino or otherwise), should the variable declarations be OUTSIDE all the code (global) or inside each function (local)?

I know that in a large program, using local variables saves the grief of having to come up with unique names... that's not what I'm asking.

From a speed and/or code size standpoint, is there any reason to use one method over the other?

Or, let me ask in a different way: Let's say I have two different functions. Both utilize a simple "for" loop.

Let's say I use uint32_t x; (4 bytes / 32 bits) in both functions. Am I correct in assuming that if instead I use ONE global uint32_t that it saves 4 bytes?

I know this example is trivial, but it can add up significantly in a large program.

Thanks for any replies!

-- Roger

General rule of thumb:

Variables should be defined in as narrow a scope as possible.

Prefer:

void foo() {
  uint32_t myLocalVar1 = 4;
}

void bar() {
  uint32_t myLocalVar2= 7;
}

to:

uint32_t myGlobalVar;

void foo() {
  myGlobalVar = 4;
}

void bar() {
  myGlobalVar = 7;
}

Both function-level (local) variables are allocated on the stack as they are needed and released afterwards. The global is there all the time whether it's being used or not.

Local variables won't conflict with each other if named the same. You can call the functions in any order, have a function call itself (recurse) etc without needing extra variables for each recursion level, etc.

I agree with majenko, mostly. If functions need to share values, passing by argument is preferred. But, global variables have one big advantage in that they retain their values from one iteration of the function to the next. Yes, static variables do, too, but passing a reference to a static variable to another function is confusing, in my opinion. Variable that need to persist values AND be shared are candidates for being global.

PaulS:
I agree with majenko, mostly. If functions need to share values, passing by argument is preferred. But, global variables have one big advantage in that they retain their values from one iteration of the function to the next. Yes, static variables do, too, but passing a reference to a static variable to another function is confusing, in my opinion. Variable that need to persist values AND be shared are candidates for being global.

Agree completely. Shared and keep their value = global. Not shared and keep their value = local static. Everything else local.

Let's say I use uint32_t x; (4 bytes / 32 bits) in both functions. Am I correct in assuming that if instead I use ONE global uint32_t that it saves 4 bytes?

Yes, a single global uses half the RAM as two locals, the RAM used is in a different place but it's still RAM. That said the global uses the RAM forever, locals only use RAM when the function is executing so in that regard locals can be seen as using less RAM because when the functions aren't running there is no RAM usage for the variable(s) at all.

However space saving to this extent is almost never a consideration, robust and understandable code is, so as Majenko says try to keep the variable scope as narrow is possible/appropriate. IE, normally use locals.


Rob

Graynomad:

Let's say I use uint32_t x; (4 bytes / 32 bits) in both functions. Am I correct in assuming that if instead I use ONE global uint32_t that it saves 4 bytes?

Yes, a single global uses half the RAM as two locals, the RAM used is in a different place but it's still RAM. That said the global uses the RAM forever, locals only use RAM when the function is executing so in that regard locals can be seen as using less RAM because when the functions aren't running there is no RAM usage for the variable(s) at all.

However space saving to this extent is almost never a consideration, robust and understandable code is, so as Majenko says try to keep the variable scope as narrow is possible/appropriate. IE, normally use locals.


Rob

THAT was what I was looking for. Thank you. What I didn't know was that local variables do not consume memory unless they are used.

Of course, thinking about it... that makes sense since one cannot return a local variable from a function. Gee... I should have known.

that makes sense since one cannot return a local variable from a function

Yes, you can.
What you can't (OK, shouldn't) do is return a pointer to a local, unless it is static.

This has helped me as well - in a nutshell my understanding is now

Variables/constants declared in the code physically ahead of the setup loop are global, and remain in existence during the execution of the sketch. They need unique names. They can be referenced within functions via "call by reference" (which is new to me as of a few minutes ago!)

Those declared locally within a function are created when the function is invoked, and are destroyed on exit. Their names need only be unique within the function, (But may not be duplicates of globally declared names? This would be bad practice in any case!).

Phew - COBOL no longer rules OK!

using local variables saves the grief of having to come up with unique names.

Variables should, in general, have names that reflect what they are for, so inventing unique names is not usually a problem.

What about Strings? in regard to memory de-fragmentation etc. Is there any difference??

(Let's forget that lot of you don't like Strings, and that string defragmentation is fixed (?) in 1.5.5)

On many places in my code, i need a quick way to store a String temporarily. For this, i use a global String variable, that is only used for this purpose. Instead of having a String variable in every method/function.

For example.

String tmpStr;

void Setup(){
tmpStr.reserve(200);
....

void x(){

tmpStr = readLineFromTxtFile();
Serial.print(tmpStr);

...

void y(){

tmpStr = "hello planet";

doSomething(tmpStr);
..

etc.

of course, this requires to always initiate the variable before using it, since we never know what's stored in there from the last time used.

I also have a global strBuf[200] variable for quick use in different places.

A positive side is that i alway know how much heap space i have to deal with and minimizes the stack-heap collision.

Also, i'm lazy. so with this method, i don't have to declare the tmpStr in every function. :slight_smile:

Am i totally wrong about my theory?
Please Enlighten me

With that method you are basically setting aside 200 bytes that can never be used by anything else for the few times when you will want to do some string manipulation.

All the rest of the time that 200 bytes is completely wasted.

Far far better to only declare the temp string as and when you need it, then the space is recycled afterwards so it can be used for other things instead. And remember - local variables are allocated on the stack in a linear fashion, not on the heap.

And as for Strings - don't even go there :wink: It's more than just heap fragmentation - it's the whole multiple objects created with lots of memory being copied around the place just to do simple operations.

majenko:
With that method you are basically setting aside 200 bytes that can never be used by anything else for the few times when you will want to do some string manipulation.

All the rest of the time that 200 bytes is completely wasted.

Far far better to only declare the temp string as and when you need it, then the space is recycled afterwards so it can be used for other things instead. And remember - local variables are allocated on the stack in a linear fashion, not on the heap.

And as for Strings - don't even go there :wink: It's more than just heap fragmentation - it's the whole multiple objects created with lots of memory being copied around the place just to do simple operations.

I ment the stack of course, not the heap! :slight_smile:

You're right, when you put it that way. I am wasting those precious 200Bytes at all times. You convinced me, as easy as that! :slight_smile:

Regrding String; i know, i know... but they're so handy at times that one just can't stand using them.

.substring(), charAt(), split() etc is functions that are priceless.
Of course, one could always do String(strBuffer).substring(), but is that really better than using the String variable?

one just can't stand using them.

Absolutely spot-on.

.substring(), charAt(), split() etc is functions that are priceless.

Maybe someone should knock up a set of functions that do this on char arrays. It's probably just a matter of pirating the code from String, changing the interface and making a few other mods.


Rob

.substring(), charAt(), split() etc is functions that are priceless.

Worthless, not priceless. They simply implement C string functions so you can use them without bothering yourself with how they work. Instead, you have to learn how substrng(), etc. work. How that is easier, I don't understand.

PaulS:

.substring(), charAt(), split() etc is functions that are priceless.

Worthless, not priceless. They simply implement C string functions so you can use them without bothering yourself with how they work. Instead, you have to learn how substrng(), etc. work. How that is easier, I don't understand.

As long as one can RTFM, it's quite easy i'd say. :slight_smile:
So you mean that we should invent the wheel again, and make functions that do these things? Please walk me throght the advantages in using implemented function vs writing your own.

Ok, it's quite easy to do your own functions for Substring, charAt etc . it's just a for loop with a index from...to or a charBuffer
But when it comes to IndexOf(), toFloat(), toInt() etc, it gets a little more complicated.
The easiest is to use String(charBuffer).indexOf("xxx"), but i don't know the disadvantages of doing this.
I just noticed there's a subfunction called "buffer". ie: tempString.buffer description "the actual charArray". I'm not sure how to use this though since i cannot find the manual for it.
Also, i do understand why the "pros" are against Strings, due to Memory fragmentation and that the destruction does not always work with String.
From what I've read, the String destruction problem is fixed in 1.5.5 Beta, right?
As far as memory de-fragmentation goes, doesn't String.reserve(x) fix that problem to some extent?

But when it comes to IndexOf(), toFloat(), toInt() etc, it gets a little more complicated.

Bullpoop. strstr(), atof(), and atoi().

Look at the String class. There is NOTHING that it does that is magic. It is ENTIRELY based on dealing with the underlying string (NULL terminated array of chars), using the standard string handling functions. Learn to use them yourself.

As long as one can RTFM, it's quite easy i'd say.

As opposed to reading a F**king book? Or using google?

As far as memory de-fragmentation goes, doesn't String.reserve(x) fix that problem to some extent?

"To some extent" and "completely" are not the same thing. If you KNOW how big the underlying string needs to be, you don't need the String class to hide it from you.