aboutsummaryrefslogtreecommitdiffstats
path: root/docs/source/arduino/goto.rst
blob: b19d424626a334ba9a48890d06a92ccceab9c4ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
.. highlight:: cpp

.. _arduino-goto:

Labels and goto
===============

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; :ref:`see below <goto-when-to-use>`
   for a concrete example.

Using Labels and goto
---------------------

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 :ref:`loop <arduino-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 :ref:`variable <arduino-variables>` 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
:ref:`serial monitor <ide-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 :ref:`if <arduino-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);
    }

.. _goto-when-to-use:

When to Use goto
----------------

As mentioned above, use of ``goto`` is `generally discouraged
<http://en.wikipedia.org/wiki/Goto#Criticism_and_decline>`_.  However,
when used with care, ``goto`` can simplify certain programs.  One
important use case for ``goto`` is breaking out of deeply nested
:ref:`for <arduino-for>` loops or :ref:`if <arduino-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 :ref:`analog reading
<arduino-analogread>` 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 :ref:`break <arduino-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.

See Also
--------

- Dijkstra, Edsger W. `Go To Statement Considered Harmful <http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.92.4846&rep=rep1&type=pdf>`_ (PDF)

- Knuth, Donald. `Structured Programming with go to Statements <http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf>`_ (PDF)