liveBook · Manning

Goto

As explained in Modern C, Third Edition

goto is a C jump statement that transfers execution to a labeled statement within the same function.

A label marks a statement; `goto` transfers execution to that label. In `if (j <= n) goto AGAIN;`, execution returns to `AGAIN` instead of continuing past the `if`. The label is visible throughout its function, but a `goto` cannot jump into another function. section 13.3 section 15.6

One cleanup path

Suppose `realloc` fails while a function is building an output buffer. The failure branch can record an error and `goto CLEANUP;`; the cleanup code then calls `free`. This keeps exceptional exits together without nesting the normal printing path inside further `if-else` statements. section 15.6

Listing 15.2 Printing an array of numbers, optimized version
int fprintnumbers_opt(FILE*restrict stream,
                  char const form[restrict static 1],
                  char const sep[restrict static 1],
                  size_t len, size_t nums[restrict static len]) {
  if (!stream)       return -EFAULT;
  if (len && !nums)  return -EFAULT;
  if (len > INT_MAX) return -EOVERFLOW;

  int err = errno;
  size_t const seplen = strlen(sep);

  size_t tot = 0;
  size_t mtot = len*(seplen+10);
  char* buf = malloc(mtot);

  if (!buf) return error_cleanup(ENOMEM, err);

  for (size_t i = 0; i < len; ++i) {
    tot += sprintf(&buf[tot], form, nums[i]);
    ++i;
    if (i >= len) break;
    if (tot > mtot-20) {
      mtot *= 2;
      char* nbuf = realloc(buf, mtot);
      if (nbuf) {
        buf = nbuf;
      } else {
        tot = error_cleanup(ENOMEM, err);
        goto CLEANUP;
      }
    }
    memcpy(&buf[tot], sep, seplen);
    tot += seplen;
    if (tot > INT_MAX) {
      tot = error_cleanup(EOVERFLOW, err);
      goto CLEANUP;
    }
  }
  buf[tot] = 0;

  /* print whole line in one go */
  if (fputs(buf, stream) == EOF) tot = EOF;
 CLEANUP:
  free(buf);
  return tot;
}

The optimized number-printing function shows a failure branch jumping toward shared cleanup after `realloc` fails. section 15.6

TAKEAWAY — Keep the jump narrow and its effects visible.

  • Prefer structured conditionals and loops for ordinary control flow. Reserve `goto` for exceptional changes, particularly local error cleanup. section 19.0 section 19.3
  • Do not jump over variable initializations. A label’s function-wide visibility does not make such a jump a good design. section 15.6
  • Check local-object lifetime when replacing a loop with a jump: similar-looking repetitions need not leave the same objects alive. section 19.3

A jump is not another loop iteration

A `while` body creates a new local compound-literal instance on each iteration; a pointer to it cannot safely be used after that body ends. In the comparable `RETRY:`/`goto RETRY;` form, the compound literal belongs to the surrounding block and remains alive until that block is left. The longer lifetime can also keep resources occupied unnecessarily. section 19.3

Listing 13.3 A contrived example for the use of a compound literal
void fgoto(unsigned n) {
  unsigned j = 0;
  unsigned* p = nullptr;
  unsigned* q;
 AGAIN:
  if (p) printf("%u: p and q are %s, *p is %u\n",
                j,
                (q == p) ? "equal" : "unequal",
                *p);
  q = p;    1 
  p = &((unsigned){ j, }); 
  ++j;
  if (j <= n) goto AGAIN;
}

Following `AGAIN` shows a subtler consequence: a jump can pass over the compound literal’s definition without making the later pointer use invalid. For `fgoto(2)`, the reported pointers are equal on the second printed line, as required by the stated C-standard rule. section 13.3

How Modern C, Third Edition covers it

How deep it goes
Defines label visibility and jump limits, gives cleanup guidance, and works through compound-literal lifetimes; does not elaborate a general jump-based design method.
Examples
Uses an optimized printing function’s cleanup jump, a labeled repetition, and contrasting while-loop and goto compound literals.
What it assumes
Assumes familiarity with C functions, loops, pointers, and local objects; introduces labels and goto explicitly.
What you can do after
Build it from scratch: write function-local cleanup jumps while avoiding skipped initializations and checking local-object lifetimes.
How it connects
Connects goto to labels, structured control flow, basic blocks, error handling, variable initialization, and compound-literal lifetime.

Also explained in

Compare how 2 books explain goto →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C, Third Edition. The section links point to the parts of the book it draws on.