No satisfactory place to define variables?

Using the Arduino/C IDE, I find there is no satisfactory place to define variables. As far as I can tell, there are 3 places that variables can be defined, and none of them are satisfactory.

(a) You can define your variables right at the start, before setup() or loop(), in the same place that you include libraries etc. However, variables defined here are global, meaning seen inside all of the functions you define, so this is clearly not satisfactory except in special cases where you wish the variable(s) to be global, or in very simple programs.

(b) You can define variables in setup(), but these will only be seen in setup(), which is generally useless.

(c) You can define variables in loop(), but then you can't initialize them in setup(), because they won't be seen there. Furthermore, you can't in any useful way initialize them in loop() either, because they will be re-initialized on every iteration of loop().

What am I missing? As far as I can see, there is nowhere you can define your variables, have them initialized once, and not be global.

The only way I can see around this, is to treat setup() as your main program, which of course will include an endless loop, and never use or execute loop().

Is it me that is nuts, or the rest of the world. :D

Mostly in the microcontroller world we don't mind using globals. They're not so bad a thing in this context.

But if you want to initialize variables in the loop() function and keep them local to that, then that is pretty easy too. If you don't want them re-initialized every time through then make them static.

static int var = 0;  //Only gets initialized the first time the function is called and persists between function calls.

You can create a class and put your variables in there.

But really, there is nothing wrong with having global variables in your program. if some teacher has told you it's wrong, well, it isn't.

Where would you have defined them (and how) in a non-arduino environment?

Don't forget that you can always have loop() not ever return... (or for that matter, have setup() never return, so the sketch never gets to loop() at all.)

But it sounds like "static" is close to what you want.

Delta_G:
Mostly in the microcontroller world we don’t mind using globals. They’re not so bad a thing in this context.

But if you want to initialize variables in the loop() function and keep them local to that, then that is pretty easy too. If you don’t want them re-initialized every time through then make them static.

static int var = 0;  //Only gets initialized the first time the function is called and persists between function calls.

Yes, that is another way around the problem, thanks.

I’m used to writing large, complex programs in high level languages where it would be almost unthinkable to have all variables global. The sheer hell and confusion that this would cause doesn’t bear thinking about.

The only advantage I can see in global variables is a small increase in efficiency, but rarely is this an issue in practice, especially with the fast micros available today. In any event, if execution speed was really important you wouldn’t be using Arduino in the first place. It is not for nothing that the C language (and even very old languages like Fortran) have mechanisms for passing parameters to and from functions, while having local variables within the function.

If you need simple initialization with fixed values, static local variables are good. If you need more dynamic and complex initialization, you will have to create a class and instantiate it in setup(). Then maybe put some functions in a while loop inside setup and pass the instance's pointer to that function for use. What are you trying to do exactly?

I'm used to writing large, complex programs in high level languages where it would be almost unthinkable to have all variables global.

I'll repeat my question; where would you put them? Surely having large numbers of local variables in main() would be nearly equally bad, and the only difference wrt variables between main() and loop() is that loop() will reinitialize them if they're initialized. Aside from that, Arduino can have local variables in any function, or dynamically allocated structures, just like most HLLs.

On small microcontrollers, it's not usually the execution time that leads to the increased desirability of global variables, but the overall SMALLNESS of memory, and some need for determinism. Dynamically allocated memory has (sometimes substantial) space overhead, and it's usually very bad if you run out (yeah, you can add checking, but ... THEN what?) If the majority of your variables are global or static, then the compile-time reporting will tell you exactly how much you've used.

qwerty99: I'm used to writing large, complex programs in high level languages where it would be almost unthinkable to have all variables global. The sheer hell and confusion that this would cause doesn't bear thinking about.

Quite right too. One of the criticisms made against Toyota in the recent court case concerning unintended acceleration was that the ETCS software involved had 11000 global variables.

qwerty99: The only advantage I can see in global variables is a small increase in efficiency...

No, it is usually more efficient to declare variables as locally as possible - that is, within the smallest enclosing { }. This gives the compiler a chance to keep the variable in a register for most or all of the time. On some processors, it also results in shorter code even when the variable cannot be kept in a register all the time, because fewer bits are needed to represent a stack-pointer relative address than a fixed address.

Throw a static boolean into loop that controls whether to run an initialization function and you're back in the same place you'd be if you had access to main - you can initialize and allocate to your heart's content. Then none of your other functions can see those variables without you passing them & voila, information hiding.

Variables are either local, or they're global. If you need to share data between two functions then you either use a global, or you pass the data as a parameter to the target function.

What is your great aversion to globals?

For the sake of neatness you can group globals into a class, and create a global instance of that class, but it's still ultimately a global variable.

A local static variable is just a local variable with global storage. Only the scope of the variable is different to a full global.

Question to qwerty99 : Are you writing Large Complex Programs for the Arduino - or is it just 3-5 pages worth of code?

Principles are good, and Practical equally so - each has their strength and weaknesses defined by the enviroment. Or, as others are conveying - keep in mind that for a small (realitivly speaking) microprogram you do not need to adhere to the strictest programming practices.

We could have the same discussion on modularizing into seperate files, classes, libraries and so on.

qwerty99: I'm used to writing large, complex programs in high level languages where it would be almost unthinkable to have all variables global. The sheer hell and confusion that this would cause doesn't bear thinking about.

In that case you need to bear in mind that in this context 'global' just means global to the compilation unit that you have defined them in. By the time your sketch became complex enough for a single pool of global data to become an issue, you ought to be encapsulating different functional areas and their associated data and types into separate compilation units. And before you got far down this road, you ought to be adopting OO methodologies. At the end of the day an Arduino sketch is just a C++ application with a bit of mucking about done to the .ino files. The rest of the world thinks that C++ is perfectly adequate to develop multi-million-line applications and if you haven't figured out how to do it then I suggest you look for C++ tutorials.

in this context 'global' just means global to the compilation unit that you have defined them in.

Um. No. In fact, it is a significant problem in "large C programs" when multiple compilation units define global variables with the same name. The linker doesn't necessarily do what you'd expect.

Msquare: Question to qwerty99 : Are you writing Large Complex Programs for the Arduino - or is it just 3-5 pages worth of code?

Principles are good, and Practical equally so - each has their strength and weaknesses defined by the enviroment. Or, as others are conveying - keep in mind that for a small (realitivly speaking) microprogram you do not need to adhere to the strictest programming practices.

We could have the same discussion on modularizing into seperate files, classes, libraries and so on.

quite true. we always see people running into problems in arduino brag how they work in this and that project.

as to the suggestion to move variables into a class, wouldn't that class still need to be instantiated as a global ? its still the same issue, just wrapped in a class.

Consider:

void setup() 
{
}

void main()
{
  // define local variables

  while(true)
  {
    // your program here
  }
}

No?

doughboy: as to the suggestion to move variables into a class, wouldn't that class still need to be instantiated as a global ? its still the same issue, just wrapped in a class.

Yes, but it avoids the issue with accidental variable overloading. GlobalVar.variableName will always be distinct from variableName declared local in a function.

It ought not to be too difficult (within the size limitations of Arduino code) to devise a scheme for the names of variables so that the chances of accidentally using the same name in two places is nil for all practical purposes.

...R

Robin2: It ought not to be too difficult (within the size limitations of Arduino code) to devise a scheme for the names of variables so that the chances of accidentally using the same name in two places is nil for all practical purposes.

You would think, and yet...

It is perfectly possible, yes. Pretty stupid, but possble. Include the full scope in the variable name.

const int global_pins = 3;

void setup() {
  int setup_Variable1 = 6;
  pinMode(setup_Variable1, INPUT);
  for (setup_for_iterator=0; setup_for_iterator < global_pins; setup_for_iterator++) {
    pinMode(setup_for_iterator, OUTPUT);
  }
}

void loop() {
  for (int loop_for_iterator = 0; loop_for_iterator < global_pins; loop_for_iterator++) {
    digitalWrite(loop_for_iterator, digitalRead(8));
  }
}

Clashes between variable names occur most often when a library or the Arduino core itself uses a name that clashes with a name invented by the user. This problem would be avoided if all names in libraries or the core were inside namespaces or classes. Most libraries follow this pattern.