Name | Description | Notes | Source | Availability | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
goto |
Jump to statement | L | Keyword | C89 | C90 | C95 | C99 | C11 |
Name | Description | Notes | Source | Availability | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
jmp_ |
Stored execution state | T | <setjmp.h> |
C89 | C90 | C95 | C99 | C11 | |||
longjmp() |
Restore execution state | (·) | <setjmp.h> |
C89 | C90 | C95 | C99 | C11 | |||
setjmp() |
Record execution state | (·) | <setjmp.h> |
C89 | C90 | C95 | C99 | C11 |
Execution within a function can jump abruptly to another
location in the same function using the goto
statement. The new location must be marked with a
label.
- statement
goto-labelled-statement
- goto-labelled-statement
identifier : statement
There are few situations where a goto
improves a function. One case is in tidying up multiple
resources after allocation of one of them fails. For example,
in this function, the allocation of the components
foo
, bar
and
baz
can be re-arranged without having
to redesign the deallocation in the case of failure part-way
through:
struct state *create_new_state(void) { struct state *result = NULL; result = malloc(sizeof *result); if (!result) return NULL; result->foo = NULL; result->bar = NULL; result->baz = NULL; result->foo = allocate_foo(); if (!result->foo) goto failure; result->bar = allocate_bar(); if (!result->bar) goto failure; result->baz = allocate_baz(); if (!result->baz) goto failure; return result; failure: free(result->foo); free(result->bar); free(result->baz); free(result); return NULL; }
However, some may reasonably argue that it is better to use other techniques such as this:
struct state *create_new_state(void) { struct state *result = NULL; do { result = malloc(sizeof *result); if (!result) return NULL; result->foo = NULL; result->bar = NULL; result->baz = NULL; result->foo = allocate_foo(); if (!result->foo) break; result->bar = allocate_bar(); if (!result->bar) break; result->baz = allocate_baz(); if (!result->baz) break; return result; } while (0); free(result->foo); free(result->bar); free(result->baz); free(result); return NULL; }
Then again, one could also argue that this is an obscure
use of do
that does not lend itself to
readability.
C permits a program to jump back to an earlier execution
state, even in a different function, by storing that state in
a jmp_
.
#include<setjmp.h>
int setjmp(jmp_buf env); _Noreturn void longjmp(jmp_buf env, int val);
The function setjmp
records the current state in env
and
returns zero. Later, longjmp
causes execution to return to the state in env
, such that the setjmp
call that saved the state returns again, but with
the specified value val
(or with
1
if val
is
zero).
This facility is to be used with great care. It only
deallocates automatic variables created between
saving and restoring the state, not dynamic variables, or any other
allocated resources like streams opened in the interim. If these
are referenced only by local variables, such resources cannot
be recovered or deallocated during the remainder of the
program's execution, and constitute a resource leak. To avoid
such errors, functions that call longjmp
should be properly documented as such, along with any
functions that call such functions. Meanwhile, intervening
functions should take care to ensure that allocated resources
are reachable via static objects before calling
longjmp
directly or indirectly.