NEWBIE question about Functions

Hello,
I am writing a arduino sketch. I am looking to put parts of the program in a function (sub routine).
I know I need a void SETUP () and a void LOOP().
If I create several other parts of the program as functions, does it make any difference where I type in the functions? Before or after the SETUP or LOOP functions?
I have gotten a few out of scope errors, I am now working to move them the top to make them global. With some of the libraries I am calling, I am finding I need to make similar variables to equate so and can work with the values in other functions?
Headed in the right direction?

Thank you

No, you need a setup and a loop function.

In the Arduino environment, it shouldn't.

But you haven't shown your code, or your problems.

2 Likes

I would suggest reading about scope in C++
It will really help you a lot in the long term, even though it may seem like a needless hassle. But it can really confusing otherwise.

Just to give you a (somewhat incomplete) example:

void myFirstScopeFunction() {
int x = 1;
}

void myOtherScopeFunction () {
int x = 6;
}

What is the value of x? Is one overwriting the other?
In the scope of the first function, it is 1, and 6 in the other. Which value is used will depend on which function is called.
It of course gets a lot more complicated than this, but I hope it will allow you to see that scope is essential info needed to write own functions.

Happy coding :+1:

1 Like

I don't think the complier cares where you write the function .... But the actual function code shouldn't be inside setup() or loop(). It CAN be called from setup() or loop(),

There are 3 "similar looking" parts:

  1. The function prototype (or "declaration"). Normally that goes in the beginning.
  2. The actual function code. Normally those are at the end after the main program or main loop().
  3. One or more function calls where execution diverts to the function and then returns. (Similar to a subroutine.) The function calls can be inside setup() or loop() or inside another function.

Sometimes the prototype and actual function are in a separate file.

Unlike a subroutine, a function can optionally return ONE value. Along with "variable scope" means that you have to use "tricks" to alter more than one variable. Or you can use gobal variables which are generally considered "bad practice" in C++ but I often use global variables because it doesn't seem "so bad" with a little self-contained Arduino "sketch".

You can pass-in multiple values, but with regular variable the function just changes the local value, and the original variable remains unchanged.

2 Likes

For defining your functions it doesn't really matter too much where you define them, most people tend to have them after the setup() and loop() functions. The compiler usually takes care of creating a function prototype for you... but there are some exceptions (for example if your function has parameters that have default values), and in these cases you need to define the prototype yourself, at the beginning of the program (before the function gets called).

As for variable scope that is something different. You can define everything as global, but it is generally considered bad practice, as you end up with code that is tightly coupled - that is, that functions are now all tied together as they operate on the same variables. This type of code is harder to debug, and less portable - you can't just copy a function and expect it to work in another program, because it relies on global variables.

1 Like

Really nice points in the posts above.

A couple of gotchas:
It is only the Arduino IDE that doesn't care about not declaring a function (prototype) prior to the first use of the function in your code (calling the function).
I try to make it a habit to declare all my functions even before setup()

Note different syntax when declaring/defining/calling a function:
don't forget the semi-colon at the end of a declaration (prototype), don't put type before function name when calling the function, etc

Completely wrong advice. The real answer to your question is that x is equal to 1 in your first function for the duration of the function, and when the function ends x is no longer a variable at all. The same is true of your second function where x is equal to 6 for the whole function and when that function ends the variable x is no longer a variable.

Any variable that is defined inside a function is said to be local to that function, any reference to a local variable outside the function it is declared in will cause a compiler error because the variable will be out of scope.

Think about this:

  • You can define any number of functions, in any order in the source code files

  • The definition (providing the code for) of a function does not mean yet: it is also called and executed (definition is not using/calling).

  • The execution of the code happens only if you call this function. And in which order they executed depends on the sequence of code with calling those functions.

  • In which order they were defined - does not matter (as long as they are defined or you need a declaration to resolve how to find those functions, e.g. their parameter list, often called "prototypes" - the hint about their "usage").

You can even call a function which sits in a LIBrary: you do not have any code, it was already compiled and sits as code in a LIB file. When you have the declaration how this functions was defined (their types, the parameter list, return types) - you can even call such a function which is not "actively" coded in your project (the linker will resolve to take the code for it from a LIB).

There is only one condition where the order of definition matters:

  • You can define a function (code the function) before you use it (later, down in your code file)

  • Assume as: "as long it is know already - all fine": you can define and use later

  • You do not need a declaration (or prototype) - the compilers saw it already before

But when you use include files, "prototypes", declarations, e.g. you define a function as extern or as available anywhere, just tell compiler how the usage is - it can be in any order, even anywhere in other files (the linker will try to find).

So, the best approach is: declare everything before you want to use (include files, "prototypes").
Otherwise: only what is known already can be used (e.g. a definition of a function before the first use - in the same file).
When it comes to using functions located in different files - you must have a declaration (include file, extern, prototype) about "what is in another files".

An exaggerated example of variable scope... x is defined 4 times in this example (not something you'd likely do in the real world), that shows how its value depends on where you are in the program at any point in time.

int x = 10;


void setup()
{
  Serial.begin(115200);

  Serial.print("at top of setup x = ");
  Serial.println(x);

  int x = myFunction(30);
  
  Serial.print("at bottom of setup x = ");
  Serial.println(x);
}

void loop()
{

}

int myFunction(int x)
{
  Serial.print("at top of myFunction x = ");
  Serial.println(x);

  for (int x = 0; x < 3; x++)
  {
    Serial.print("inside for loop x = ");
    Serial.println(x);
  }
  
  Serial.print("at bottom of myFunction x = ");
  Serial.println(x);

  return x + 15;
}
10:42:15.785 -> at top of setup x = 10
10:42:15.785 -> at top of myFunction x = 30
10:42:15.785 -> inside for loop x = 0
10:42:15.785 -> inside for loop x = 1
10:42:15.785 -> inside for loop x = 2
10:42:15.785 -> at bottom of myFunction x = 30
10:42:15.785 -> at bottom of setup x = 45

1 Like

This is "scope of variables".
You can have the same variable name as a local (auto) variable or as global, "outside" variable.
As long as compiler can find "any" variable x - it would be fine.

And it tries to find (resolve) the variable x by searching through a well defined list of scope: first find it as local (just internal to function), if not there - find it outside the function.
If it is even not outside, but somewhere is an "extern" - compiler assumes it is somewhere else and the linker will resolve (when binding all files together).

As mentioned already here: important to understand the scope of local variables (such as defined inside the function): only available and visible when executing the code inside the function. The variable x, when local is only visible for the code of this function.

If the variable x would be sit outside - it generates side effects: now it can be seen by different functions using it, also the main() program. It is a shared variable: any change becomes visible in the other functions (at it is visible in the other functions as the same variable).

The scope of variables matters - which depends where they are defined (inside vs. outside) and how compiler could find and see them.

Mike, you missed the point I was trying to make to the OP.
The questions about the value of x were rhetorical.

I was using that as an example of how you cannot assume the value of x unless you know which function was being called. I deliberately chose not to go on but leave it as a teaser to encourage the OP to explore.
Please read the very first line of my post to the OP.

The advice was to read up on scope to better understand how to write functions. Since the OP has not responded to my comment, I can't say if that point got across :grin:

What is OP?
(do you assume Arduino team (as OP) is reading here? I do not think so, more a user forum).

Sure, if x is a global and shared variable - the function call sequence matters what is left in x.
(a 'side effect' is always hard to "understand" - better to avoid to have it).

Original Poster... the person that created the topic.

OP = original poster, as per @red_car
And so far, not seen any response from them.

Oh, I see. Thank you.
Let's see if OP has gotten the thing with the scope. :smiley:

1 Like

Thank you

1 Like

the replies have helped me figure out what I need to do. I hope to spend time tomorrow putting some changes into effect

Thank you for your replies and help.
I think I have a better idea of how functions and scope work. I will see tomorrow when I make a few changes and see how it goes.

1 Like

This is the power of globals, they let independent-running code tasks share signals.

In small code, globals can be kept clean and not "dangerous". But when the code gets big, you wat as much of it self-contained as possible, that's where C++ really shines.

Hey HenryJD !

Arduino Learn main page. Bookmark and explore!

Arduino using functions page.

Your right