Next: , Previous: , Up: Statements   [Contents][Index]


19.12 goto Statement and Labels

The goto statement looks like this:

goto label;

Its effect is to transfer control immediately to another part of the current function—where the label named label is defined.

An ordinary label definition looks like this:

label:

and it can appear before any statement. You can’t use default as a label, since that has a special meaning for switch statements.

An ordinary label doesn’t need a separate declaration; defining it is enough.

Here’s an example of using goto to implement a loop equivalent to dowhile:

{
 loop_restart:
  body
  if (condition)
    goto loop_restart;
}

The name space of labels is separate from that of variables and functions. Thus, there is no error in using a single name in both ways:

{
  int foo;    // Variable foo.
 foo:         // Label foo.
  body
  if (foo > 0)  // Variable foo.
    goto foo;   // Label foo.
}

Blocks have no effect on ordinary labels; each label name is defined throughout the whole of the function it appears in. It looks strange to jump into a block with goto, but it works. For example,

if (x < 0)
  goto negative;
if (y < 0)
  {
   negative:
    printf ("Negative\n");
    return;
  }

If the goto jumps into the scope of a variable, it does not initialize the variable. For example, if x is negative,

if (x < 0)
  goto negative;
if (y < 0)
  {
    int i = 5;
   negative:
    printf ("Negative, and i is %d\n", i);
    return;
  }

prints junk because i was not initialized.

If the block declares a variable-length automatic array, jumping into it gives a compilation error. However, jumping out of the scope of a variable-length array works fine, and deallocates its storage.

A label can’t come directly before a declaration, so the code can’t jump directly to one. For example, this is not allowed:

{
  goto foo;
foo:
  int x = 5;
  bar(&x);
}

The workaround is to add a statement, even an empty statement, directly after the label. For example:

{
  goto foo;
foo:
  ;
  int x = 5;
  bar(&x);
}

Likewise, a label can’t be the last thing in a block. The workaround solution is the same: add a semicolon after the label.

These unnecessary restrictions on labels make no sense, and ought in principle to be removed; but they do only a little harm since labels and goto are rarely the best way to write a program.

These examples are all artificial; it would be more natural to write them in other ways, without goto. For instance, the clean way to write the example that prints ‘Negative’ is this:

if (x < 0 || y < 0)
  {
    printf ("Negative\n");
    return;
  }

It is hard to construct simple examples where goto is actually the best way to write a program. Its rare good uses tend to be in complex code, thus not apt for the purpose of explaining the meaning of goto.

The only good time to use goto is when it makes the code simpler than any alternative. Jumping backward is rarely desirable, because usually the other looping and control constructs give simpler code. Using goto to jump forward is more often desirable, for instance when a function needs to do some processing in an error case and errors can occur at various different places within the function.


Next: Locally Declared Labels, Previous: Null Statement, Up: Statements   [Contents][Index]