Arduino 1.6.5 and a 'Funduino'. Have successfully got a 20*4 LCD running via I2C and an LM35 (temp sensor) and pot as analogue inputs - so not too shabby.
My problem is incrementing a local variable within the main 'loop'. I used to teach 'C' about a million years ago, so I am familiar with the scope of local and global variables (global vars being devils work).
So, I declare my local variable 'int tenths;' within the 'loop' main function, and attempt to increment it further on in 'loop' - but it won't have any of it. I've done all the usual things like adding 1 to itself, pre-inc, post-inc etc, but it just does it one-time only. If I make the variable 'global', it works fine - so my code is OK. It's as if the var gets reset to zero, each time the 'loop' runs (I'm not setting it to zero when I declare it).
Obviously local vars are preferable in order to stop mischievous functions from tinkering with them.
There's lots of things wrong with global variables. They should be avoided wherever possible. If a particular variable only needs to be used inside one function then it is better to make it local, and static if necessary.
This choice is not set in stone - you can change it in your program later if you decide that it needs to be accessed in multiple functions. That kind of change often means that you should be using a class instead of a bare function.
Ok, lets put it this way. There is nothing wrong with using global variables, it is just better practice to not use them when possible.
An example of where global variable would be bad. Consider you have 10 functions and each one needs its own variable and they don't need to be static. If you declare them global then you waste 10x the amount of ram, when if they were declared local the program would use only what it needed, usually 1 at a time...
Made it 'Static' - works a treat - thank you. ...and the rest for your prompt replies.
As an aside; I program every single day (just about all day) using an Israeli program called 'Rapid' - if I used global variables I would soon tie myself in knots. I have to modularize my code (functions), use local vars within, and strictly pass any data back and forth. Otherwise, debugging would be a nightmare. My software engineering textbooks strictly advocate this too.
Nothing wrong with global variables in a microcontroller that's bound to a
specific piece of hardware, since you can't create duplicate hardware at will...
Its when software is unconstrained from hardware that global variables then
become a constraint in themselves. Particularly if you are coding a library
that could be used many times by the same program - you then want to
keep state bound to a context or object to allow multiple active incarnations
of the code (ie it can be re-entrant in the same thread, work indepedently
for each thread, etc).
You shouldn't ever learn a rule before understanding when and why it
has to be broken!
guix:
Static local variables are not better than global variables in any way, they are both the same thing, the only difference is scope.
But I prefer using static locals whenever possible, it makes the program more clear.
Wouldn't you say that "makes the program more clear" is better? Therefore static local variables are better than global variables (when you don't need the wider scope of a global variable).
Getting back to the concept of scope. Scope refers to the lifetime and visibility of a data item. As a starter, consider:.
Global scope -- data items define outside of any function. Global variables are visible from their point of definition to the end of the program file in which they are defined and live as long as the program is running.
Function scope -- data items defined within the starting ({) and end (}) braces of a function. They come to life at their point of definition when program control enters the function and they "die" (i.e., go out of scope) when control leaves the function.
Block scope -- data items defined within a statement block. They come to life (i.e., are in scope) at their point of definition within the statement block and die when the block ends. For example:
--- Code: ---
for (int k = 0; k < MAXNUM; k++) {
sum += val[k];
}
average = sum / k; // ERROR: k is no longer in scope
--- End code ---
Variable k comes alive (into scope) when its definition is read as expression1 of the for loop. It dies when the closing brace of the for loop is reached. Therefore, the statement outside the braces draws a compiler error because k no longer exists.
static -- Using the keyword static allows you define a data item with local scope, but have it retain its value even when program control goes outside its scope level. For example, if you have
--- Code: ---
void myFunction() {
static int myVariable = 10;
// more code...
myVariable++;
} // end of function
--- End code ---
the next time you enter myFunction(), myVariable will still have the same value it did after the previous call to the function ended. In other words, myVariable would equal 11 on the second call to the function because of the increment operation. Data items defined with the static type specifier are allocated on the heap, which means 1) only one of them is defined for the program, and 2) the data item persists regardless of its scope level.
Scope refers only to the visibility of a variable. The lifetime of a variable is different from its scope.
Scope is simply the "visibility" of a variable--i.e., where a variable can be referred to by name. Lifetime is simply when a variable is created and destroyed.
There are two lifetimes: static and automatic. A static variable is created at program load time and is destroyed at program exit; an automatic variable is created and destroyed automatically as needed inside a function (generally on a stack).
There are three types of scope: global, file, and local. Global scope means a variable is visible everywhere. File scope means a variable is visible everywhere inside a single compilation unit (roughly, a single source file). Local scope means it is visible only inside the block or function in which it is defined.
Here is an example code containing all valid combinations of lifetime and scope:
int a; // global scope, static lifetime
static int b; // file scope, static lifetime
void foo()
{
static int c; // local scope, static lifetime
int d; // local scope, automatic lifetime
}
A variable's scope cannot be larger than its lifetime; a variable is not visible either before it is created or after it is destroyed. This means that a variable with automatic lifetime cannot have global or file scope; it can have only local scope.
Global scope means a variable is visible everywhere.
Not quite true. If you have a variable defined in one source file with global scope, it must be declared in any other source file using the extern keyword. Also, your definition of file scope should read "from its point of definition to the end of the file in which it is defined." You can prove this by defining an int x with global scope after loop() but try to use it in setup().
Most people find it useful to separate the concepts of local (function) scope from block (statement) scope.
As to the distinction between lifetime and visibility, that's why I had the static qualifier discussed after local scope.
econjack:
Not quite true. If you have a variable defined in one source file with global scope, it must be declared in any other source file using the extern keyword. Also, your definition of file scope should read "from its point of definition to the end of the file in which it is defined." You can prove this by defining an int x with global scope after loop() but try to use it in setup().
I was playing somewhat fast and loose with the concepts. A variable with any scope is visible only after its declaration (a definition is also a declaration).
econjack:
Most people find it useful to separate the concepts of local (function) scope from block (statement) scope.
I'm not one of those people. A variable with local scope is visible only within the block in which it is defined. A variable with "function" scope has local scope and just happens to be defined in the top-level block of a function, so it's visible anywhere inside the function (after the variable's definition, anyway).
From a teaching perspective, it is useful to make the distinction, as in something like:
int myFunction()
{
int i = 10; // Function block scope
int val = 0;
for (int i = 0; i < 5; i++) { // Statement block scope
val += i * i;
}
return val * i;
}
MarkT:
Nothing wrong with global variables in a microcontroller that's bound to a
specific piece of hardware, since you can't create duplicate hardware at will...
You shouldn't ever learn a rule before understanding when and why it
has to be broken!
This is an offensive argument. Just because someone doesn't agree with you, don't belittle them by claiming they are ignorant. If your argument is valid, it will stand up by itself.
There is plenty wrong with global variables, but they also have their place. I see a lot of code on these forums that does not work and is difficult to debug specifically because people have used global variables. It's often a lazy way to program and means that different sections of the code interact invisibly with other sections of the code. By using proper data hiding the compiler can tell you about errors that are sometimes difficult to find if the data is simply globally visible. When you are a beginner, it is even more important than when you know how to track down these problems.