A label gives a name to a line of code within a function. You can label a line by writing a name for it, then a colon (:), before the line starts. The goto keyword allows program flow to transfer to a labeled line from anywhere within the same function.
Warning
The use of goto is discouraged in C and C++ programming. It is never necessary to use goto to write a program.
Unless you know what you’re doing, using goto tends to encourage code which is harder to debug and understand than programs without goto that do the same thing. That said, however, it’s sometimes useful; see below for a concrete example.
Labels and goto are probably best explained through example. Let’s start with an example of how to label lines. The first line (int x = analogRead(some_pin);) in the loop function below has label readpin. The third line (delay(x);) has label startdelay. The second line (SerialUSB.println(x);) does not have a label:
void loop() {
readpin:
int x = analogRead(some_pin);
SerialUSB.println(x); // for debugging
startdelay:
delay(x);
// ... more code ...
}
Anything which can be a variable name can be a label.
Let’s say that we wanted to print x only if it was very large, say at least 2000. We might want to do this just so anybody watching on a serial monitor would know they were in for a longer wait than usual. We can accomplish this through the use of a goto statement that skips the printing if x is less than 2000:
void loop() {
readpin:
int x = analogRead(some_pin);
if (x < 2000) {
goto startdelay;
}
SerialUSB.println(x); // for debugging
startdelay:
delay(x);
// ... more code ...
}
In this modified program, whenever x is less than 2000, the body of the if statement in the second line is executed. The goto statement inside the if body skips straight to the line labeled startdelay, passing over the line doing the printing.
A goto does not have to “move forwards”; it can go “backwards”, too. For example, the following program prints “5” forever (why?):
void loop() {
printfive:
SerialUSB.println(5);
goto printfive;
SerialUSB.println(6);
}
As mentioned above, use of goto is generally discouraged. However, when used with care, goto can simplify certain programs. One important use case for goto is breaking out of deeply nested for loops or if logic blocks. Here’s an example:
for(int r = 0; r < 255; r++) {
for(int g = 255; g > -1; g--) {
for(int b = 0; b < 255; b++) {
if (analogRead(0) > 250) {
goto bailout;
}
// more statements ...
}
// innermost loop ends here
}
}
bailout:
// more code here
In the above example, whenever the analog reading on pin 0 was greater than 250, the program would jump to the line labeled bailout, exiting all three loops at once.
While there is already a break keyword for breaking out of a loop, it will only break out of the innermost loop. So, if instead of saying “goto bailout;”, there was a “break;” instead, the program would only exit from the loop with header “for(int b = 0; b < 255; b++)”. The program would continue at the line which reads “// innermost loop ends here”, which is clearly undesirable if you wanted to leave all three loops at once.
More examples of when goto is a good choice are given in Donald Knuth’s paper, “Structured Programming with go to Statements”; see below for a link.
License and Attribution
Portions of this page were adapted from the Arduino Reference Documentation, which is released under a Creative Commons Attribution-ShareAlike 3.0 License.