Search

7.6 — Goto statements

The next kind of control flow statement we’ll cover is the unconditional jump. An unconditional jump causes execution to jump to another spot in the code. The term “unconditional” means the jump always happens (unlike an if statement or switch statement, where the jump only happens conditionally based on the result of an expression).

In C++, unconditional jumps are implemented via a goto statement, and the spot to jump to is identified through use of a statement label. The following is an example of a goto statement and statement label:

In this program, the user is asked to enter a non-negative number. However, if a negative number is entered, the program utilizes a goto statement to jump back to the tryAgain label. The user is then asked again to enter a new number. In this way, we can continually ask the user for input until he or she enters something valid.

Here’s a sample run of this program:

Enter a non-negative number: -4
Enter a non-negative number: 4
The square root of 4 is 2

Statement labels have function scope

In the chapter on object scope (chapter 6), we covered three kinds of scope: local (block) scope, file scope, and global scope. Statement labels utilize a fourth kind of scope: function scope, which means the label is visible throughout the function even before its point of declaration. The goto statement and its corresponding statement label must appear in the same function.

While the above example shows a goto statement that jumps backwards (to a preceding point in the function), goto statements can also jump forward:

This prints:

cats

Beyond the jumping forward, there are a couple of interesting things worth mentioning in the program above.

First, note that statement labels must be associated with a statement (hence their name: they label a statement). Because the end of the function had no statement, we had to use a null statement so we had a statement to label. Second, we were able to jump to the statement labeled by end even though we hadn’t declared end yet due to statement labels having function scope. No forward declaration of statement labels is necessary. Third, it’s worth explicitly mentioning that the above program is poor form -- it would have been better to use an if statement to skip the print statement than a goto statement to jump over it.

There are two primary limitations to jumping: You can only jump forward or backward within a single function (you can’t jump out of one function and into another), and if you jump forwards, you can’t jump forward over the initialization of any variable that is still in scope at the location being jumped to. For example:

Note that you can jump backwards over a variable initialization, and the variable will be re-initialized when the initialization is executed.

Avoid using goto

Use of goto is shunned in C++ (and other modern high level languages as well). Edsger W. Dijkstra, a noted computer scientist, laid out the case for avoiding goto in a famous but difficult to read paper called Go To Statement Considered Harmful. The primary problem with goto is that it allows a programmer to jump around the code arbitrarily. This creates what is not-so-affectionately known as spaghetti code. Spaghetti code is code that has a path of execution that resembles a bowl of spaghetti (all tangled and twisted), making it extremely difficult to follow the logic of such code.

As Dijkstra says somewhat humorously, “the quality of programmers is a decreasing function of the density of go to statements in the programs they produce”.

Almost any code written using a goto statement can be more clearly written using other constructs in C++, such as if statements and loops. One notable exception is when you need to exit a nested loop but not the entire function -- in such a case, a goto to just beyond the loops is probably the cleanest solution.

Best practice

Avoid goto statements (unless the alternatives are significantly worse for code readability).


7.7 -- Intro to loops and while statements
Index
7.5 -- Switch fallthrough and scoping

83 comments to 7.6 — Goto statements

  • Hi

    As one comic put it,
    https://xkcd.com/292/

  • Benali

    I have a question:

    In the example, control flow never passes the declaration of int x, how does it know the variable x when hitting x=3

    And why it does not work for if-else statements? in the following example, compiler tells me 'x' is not defined.

    • jdhtzww

      So the second example proves that control flow didn't pass the declaration of int x in the first example, since the statement label has function scope.

    • ewrilan

      definition takes place during compilation, so x is in scope at line 6 even though the place where its defined was skipped. The second example wouldn't compile even without goto, as x is destroyed at the end of else block.

  • Alan LAI

    goto is unconditional jump of assembly in high level language. Actually, jump is very useful for writing assembly code, you can jump from one function to any address and do second jump then third jump freely. However, there are so many constraints of using address and memory in high level language. Although cpp is powerful, I still remember how excited I was when I understood the useability of jumping.

  • Noman

    Lots of questions buried here.
    break only does the current scope.  If you have 3 loops deep and break in the innnermost one, it will not stop the outer two.  The goto will exit all 3 loops immediately.

    not sure how it came up but a switch statement "can" be implemented as a lookup table instead of branching which is faster. This depends on the compiler's smarts and how complex the code in the case statements is (a second good reason to keep case statements simple, the first being readability).

    variables and labels:
    variables may or may not allocate space.  Many so-called variables are actually cpu registers and never get 'allocated' on the stack at all. You have 10 or so cpu registers on most systems and the compiler can translate a local variable to use those instead of a real memory location if there is no need for the value to be preserved for long, such as a loop counter.  

    Bookmarks is a good analogy for a label, but the word 'pointer' is maybe a little more accurate.  Remember that code is also a stream of bytes in memory somewhere.  The executable statements of your program in cpu language are loaded into memory and fetched to be executed.  Goto moves the instruction pointer (a cpu register holding the address of the next instruction to execute) to the label location (just an address in the executable statements area) and the cpu dutifully fetches the next instruction from the new location.  The address is a hard coded value, so it is stored in the instruction itself (not in a variable), that is, in the cpu instructions your goto becomes jump(0x12FFb42) or something like that.  Many constants, memory addresses, and the like are stored in the cpu instructions as part of the command rather than in an actual variable.  Const int x{100} is very likely to just have the value 100 injected into instructions rather than be stored on the stack etc, for another example of this idea.

  • kio

    Hi @nascardriver and @alex,

    One notable exception is when you need to exit a nested loop but not the entire function -- in such a case, a goto to just beyond the loops is probably the cleanest solution.
    -> We could also use "break" right? it would be the clean solution?

    • nascardriver

  • Harvard's CS50 is a joke... They jump into Chapter 7 using standard C on the first class with the "Build a Mario Level Problem"... They assume you have read chapters 1-7 in this book by the 1st class. That's just meant to overwhelm and demotivate people... I was able to do the "Mario Level Problem" on my own in C++ by this point without question. God Bless you Alex!

  • kk

    isn't switch statement faster then if-else when number of cases are more than 5?

    • nascardriver

      `switch` statements should never be slower than `if` statements. They can start being faster than a linear `if` at 4 cases (As far as I can tell).

      To get to the maximum depth (d), we need 3 comparisons. The average cost is 9/4 (9 is the sum of comparisons, 4 is the number of cases).

      To get to the maximum depth (d), we need 2 comparisons. The average cost is 8/4=2 plus the goto.
      If this `switch` is faster than the `if` depends on the speed of the `goto`. If the compiler knows that the `goto` is too slow, it can always fall back to a linear check.

  • Christian

    Is this lesson broken or just me? Anyone else?

  • Jiana

    Q1:
    >The goto statement and its corresponding statement label must appear in the same function.

    Would you please give an example that violates the rule of the sentence above?

    Q2: In the code below, I initialized the variable 'w' within the function scope of go-to statement, but I still was able to print its value after the function scope finishes.why? it is confusing!

  • Alek

    hello,in the context above you say :you can’t jump forward over a variable that’s initialized in the same block as the goto.I tried to leave it uninitialized and it works fine! I wonder if you can tell me why can't it jump over an initialized variable ? what is the reason?
    2: I read @bronzdragon answer to SM.Haider he says:Statement labels aren't actually variables, so they're not allocated the same way.so how are they allocated ? how many different allocation do we have in c++ are there any websites that can extend this topic and talk about these in details?
    thanks in advance!

    • nascardriver

      If a variable has an initializer, we're safe to assume that the variable is initialized when we first use it. Jumping over the initialization would violate this, as the variable would be declared, but not initialized (Initialization occurs when control passed through the definition, but if you just over the definition, control never passes through it).

      Statement labels are not objects, they don't take up any memory, they don't get allocated.

  • Nathuunn

    what if I created a calculator and wanted to repeat the whole thing over again so i can solve another problem what should I do then?

  • Raffaello

    "Rule: Avoid use of goto statements unless necessary"
    I'm curious now, when a goto statement would be necessary? (also, shouldn't that be in a red box?)

    • nascardriver

      It's never really necessary. It can be handy for breaking out of nested loops, but even that can be done without `goto`.

  • SM.Haider

    I have a question or two;
    Once you initialize a variable, (obviously) it allocates a specific quantity of memory, so how many bytes of memory does a statement label allocate?
    Secondly, if we utilised numerous goto statements in a program, will that delay the performance of the processor?

    • Bronzdragon

      Statement labels aren't actually variables, so they're not allocated the same way.

      To keep it simple, when the compiler compiles your code, it converts your programme to byte code. Each statement translates to 1 or more instructions (or sometimes zero, due to optimization). Each instruction has a position in the code. When you create a statement label, the compiler remembers the offset to the next instruction. When you jump, it takes the address of the start of your programme, and the offset, and jumps there.

      This offset is stored directly in the instruction, it's not in any way dynamic, like variable decelerations are normally.

    • June

      Hmm to put it another way, I think the best analogy is a bookmark. To keep things simple, when you compile your program it places a bookmark next to the code beneath it. This is all the label amounts to. It doesn't make your program any bigger or smaller and doesn't take up any memory. It's just a simple bookmark that the compiler uses so that it knows where exactly to make the program jump to. Theres a lot more but I'm keeping things very simple.

      Jumping around is very crucial to some languages, notably one of my favorites, assembly. However that's not really the way of C++ outside very special cases you won't hardly encounter. If you feel like a goto statement would work well then it's usually the case to sit back a minute and rethink your program so far. Of course you can always play around with goto to delve a bit into curiosity just know that in normal C++ programs it's not really expected to be used.

      I hope I answered your question well ^_^

Leave a Comment

Put all code inside code tags: [code]your code here[/code]