I am following what Robin2 did and creating this thread so as to not turn this one into complete off-topic.
A question came up of whether it is a 'good practice' to use global variables instead of local when programming Arduino (and possibly microcontrollers in general?)
I personally tend to avoid using globals in my code because as many would probably agree:
They introduce 'uncertainties' into the code, you can never be sure that something did not change the value of a global variable
Which means they kill encapsulation
And make debugging harder
They are also a major pain in larger codebases for all of the above reasons
However some people say that there are performance benefits of using global variables over local ones.
I would really appreciate if someone could explain what those benefits are. And what are the trade-offs of using local variables?
you can never be sure that something did not change the value of a global variable
If you choose sensible names for variables then it is safer. For instance if your code is counting two different things then it would be silly to name the variables count1 and count2 when more descriptive names would be appropriate.
make debugging harder
or easier depending on your point of view
They are also a major pain in larger codebases for all of the above reasons
You need to define what you mean by a large codebase. After all, the memory available to most Arduinos is quite limited and a lot of the heavy lifting is often done by using libraries. Sensible use of suitably named functions can also reduce the pain considerably.
Use whatever method suits you and your programming style. There are those here that say that they never use functions and put all code in line whilst others advocate the use of functions at the drop of a hat. Are either of them wrong ? No, of course not.
C/C++ brings its own challenges to the party. If only you could return more than one variable from a function, for instance. Using global variables removes the need so would be a good reason to use them.
UKHeliBob:
If only you could return more than one variable from a function, for instance. Using global variables removes the need so would be a good reason to use them.
You can, easily, either using reference arguments in c++, or passing a pointer to a struct or array in either c or c++....
You can't really talk about debugging when you cannot set a breakpoint, inspect variables, see the stack.
The only "debugging" for Arduino I know is by printing out statements (try doing that when your goal to optimize memory usage).
My point of view is the following:
With local variabes you have control over each of them and can instantly see if any problem occurs and where it occurs.
With global - there is only one value and it is not obvious what could go wrong.
I am mostly interested in performance benefits of using global variables on Arduino.
You can't really talk about debugging when you cannot set a breakpoint, inspect variables, see the stack.
The only "debugging" for Arduino I know is by printing out statements (try doing that when your goal to optimize memory usage).
I agree, those points mainly apply to my general programming experience, which has very little to do with microcontrollers.
PS
Actually one could use Visual Micro or Atmel Studio for debugging Arduino.
Using global variables removes the need so would be a good reason to use them.
I agree with Ray on this one. The only reason that the need for multiple returns favors global data is when the programmer doesn't know how to use pointers properly. (I'm talking about a newbie here...I know Bob knows how to use pointers.) It would take a stronger argument than that for me to give up the benefits of encapsulation that globals toss out the window.
You can't really talk about debugging when you cannot set a breakpoint, inspect variables, see the stack.
Not only can you talk about debugging...you must talk about it within the framework that the IDE gives us. In that sense, encapsulation at least helps give you a starting place where you can put those print statements. I'm sure all of us would like a true symbolic debugger, but until that happens, debugging within the Arduino IDE is what it is...print statements.
My take on it is like this ... (in no particular order)
All variables should have meaningful names - that solves the confusion problem.
If you need static local variables the memory usage is identical to using global variables.
Non-static local variables are usually held in registers so they don't consume SRAM - which can be a significant point in their favour.
I presume there is a cost in terms of CPU cycles to create the variables in registers when a function is called - which is a point against the use of local variables.
Debugging using Serial.print() is often easier with global variables because you don't want to call the function specially to get the value for printing - it may also return a different value (e.g. millis() )
Local variables are very inconvenient when you want to use the result of a function in more than one other function. Either you need a complex cascade of functions so the value percolates upwards, or you need to save the result in a global variable - so why not use globals in the first place.
If you are part of a team with each having a specific task it probably does become essential to use local variables so that there is a clear interface for each function and no possibility of another member of the team "stealing" your global variable. If there is only one programmer (me) this is irrelevant.
The restricted scope of "local" variables can be convenient as it avoids the need to give every variable a different name. For example for (byte n = 0; n < 10; n++). Personally, I probably see more value restricting scope to things like FOR and WHILE rather than to a complete function.
I think global variables are easier for a newcomer to comprehend. And I guess a mixture of globals and locals is the most confusing.
In the Arduino environment setting out all the global variables at the top of the program makes it easy to keep track of SRAM usage.
Debugging using Serial.print() is often easier with global variables because you don't want to call the function specially to get the value for printing - it may also return a different value (e.g. millis() )
Usually debugging is tracking down where the value of a particular variable is going wrong. If the offending variable is local, at least I know where to start placing print statements. If it's global, it can be anywhere from its point of definition to the end of the current source file. I'll take local every time.
Local variables are very inconvenient when you want to use the result of a function in more than one other function. Either you need a complex cascade of functions so the value percolates upwards, or you need to save the result in a global variable - so why not use globals in the first place.
I'm not sure what you mean here. One of the things I strive for are functions that are not coupled to other functions...it helps make them reusable. Perhaps an example would help.
I think global variables are easier for a newcomer to comprehend. And I guess a mixture of globals and locals is the most confusing.
While it may be easier to understand global scope, any programmer who hopes to write something with more complexity than Blink needs to grasp the concept of scope. Would you really want to hire a programmer who doesn't understand or use scoped variables?
The only difference I know of between global vs local is that when memory for global is alloated w/o a value (e.g. int number;) - it puts zeroes in there, while for a local variable - it keeps memory content unchanged (is this even true?)
Also, aren't global variables also put into SRAM during execution? (some people say that using globals is a way to save SRAM space?)
Robin2:
Non-static local variables are usually held in registers so they don't consume SRAM
The only difference I know of between global vs local is that when memory for global is alloated w/o a value (e.g. int number;) - it puts zeroes in there, while for a local variable - it keeps memory content unchanged (is this even true?)
Global variables are allocated on the heap, local variables on the stack.
florinc:
Global variables are allocated on the heap, local variables on the stack.
Doesn't that mean that local variables are better for performance then? (i.e. faster access)
Plus global variables always occupy their space, while local variables can 'recycle' it.
Doesn't that mean that local variables are better for performance then? (i.e. faster access)
Access time is the same, both heap and stack being in RAM.
The only issue I see with the local variables (in the context of little RAM available) is that the stack grows (thus potentially running out of memory) "proportionally" with the amount of nested function calls.
This is not an issue on a PC, of course.
If you are in a scenario where your sketch runs out of RAM, what do you do? Try to call fewer nested functions, try to make local variables global, "downgrade" the ints to bytes wherever possible etc.
florinc:
The only issue I see with the local variables (in the context of little RAM available) is that the stack grows (thus potentially running out of memory) "proportionally" with the amount of nested function calls.
This is not an issue on a PC, of course.
Makes sense, thanks.
Delta_G:
That code has two global variables. Go ahead and rewrite this code to encapsulate those variables away. Make a class or whatever you want to do. Then look at the new code. Does all of that really make sense just to blink an LED? Is anyone working on the BlinkALed project going to get confused when they push their changes?
This example is too simple. Add a few more LEDs, and a couple other devices - and you'll end up in a complete mess.
But yeah, as long as you're just blinking one LED - you'll be fine using globals.
my code has 1500 line and 98 globals and most of its is written with in the main loop. The code does what is asked to do. I can trouble shoot any problem because the descriptors make sense. So do I rewrite the code to a more complicated style to make it look more professional or just except that it works.
Delta_G:
That's my point exactly. That there is a line somewhere where these things start making a difference.
My point is - this line is much closer then you think. Its not about working with other people. You will have problems even if you are the only one working on the project.
As I said - just add three more LEDs, a couple buttons and a servo (not extremely unusual setup among Arduino beginners) - and you will have a mess.
gpop1:
my code has 1500 line and 98 globals and most of its is written with in the main loop. The code does what is asked to do. I can trouble shoot any problem because the descriptors make sense. So do I rewrite the code to a more complicated style to make it look more professional or just except that it works.
Mate, there is heaps of code that 'just works' - but is still a complete nightmare to read and maintain. Just remember that the code you are writing in IDE - is not the same code that is gonna be executed on your Arduino. So why not write it properly for yourself?
This all of course depends, if your goal is to just get things working - then its fine, if you however want to improve your programming skills - you should try and follow best practices.
You really are wrong by saying that best programming practices introduce "more complicated style" - that's the opposite of what they do, the way you are writing your programs now is a lot more complicated.
And no, all those classes, functions etc. were created NOT to show how cool of programmers we are, they were created because they make the code simpler, more reusable and much easier to maintain.
"This all of course depends, if your goal is to just get things working - then its fine, if you however want to improve your programming skills - you should try and follow best practices."
90% of arduino users are just trying to get there project to work and believe me im grateful that 10% are here to improve there coding or to pass on experience. I honestly respect the people who write libraries that allow the 90% to do things that would take a college course to understand. My only bitch is don't make it complicated when it doesn't need to be. You can tell by some ones code they post which % you are talking to.
(ok maybe not as we are great at copying other peoples code with no idea what it does)
I only help new people as I understand there frustration. Then I read other peoples codes as I find it interesting not only in what they are doing but the signature that's left in the code by the way they are thinking. I have a whole file of interesting codes that ive picked up on here that I run in test sketchs I just haven't worked what ive learn into my main sketch yet.
@gpop1: I understand what you're saying, but I also think people here want to improve, perhaps moving from the 90% to the 10% group. I know I've been using C for over 30 years and I'm still learning things.
As to the 1500 lines of code and 98 globals, most of which is in loop(), I think I'd be hiding those statistics, not bragging about them. Actually, that's a medium sized program for an Arduino, but a very small program in other circumstances. (I just finished a program with over 700,000 lines of code and fewer globals than you have. See www.microstat7.com.) I'm sure your code works, but reusing the code or extending it won't be easy should the need arise because of the design choices you made now.
One of my points about using functions and local variables is that it helps isolate where things are going wrong. But then, since you have all 1500 lines of code in loop(), you already know exactly where to look for any bug...plus or minus 1500 lines. Me? Since I rarely write a function with more than 25 lines of code, that's usually about the extent of my search, since my offending local variable tells me which function is misbehaving.
As they say: There's more than one way to skin a cat. You have your way...I have my way. It's just a matter of style.