Legitimate uses of a goto

Viewed 116

To play around with the goto statement, I've rewritten a while loop in a more assembly-style loop:

// while
int i=0;
while (i++<10)
    printf("%d...", i);
// asm-ish
loop:
    i++;
    printf("%d...", i);
    if (i<10)
        goto loop;
loop_exit:
    return 0;

Outside of a sort of academic exercise, are there any real-world/useful examples of how the goto statement can be used? Or is this basically a vestigial part of c that isn't used.

Here's an example of a code file that makes extensive use of it: https://github.com/postgres/postgres/blob/ca3b37487be333a1d241dab1bbdd17a211a88f43/src/port/snprintf.c.

I suppose one thing I can think of is getting out of deep-nesting without having to use a bunch of continue/breaks, but that's about it.

1 Answers

While you can use goto in this way, it's generally considered bad style since the language has other constructs like while that do the same thing in a "cleaner" fashion.

Once place where it does make sense to use goto is to jump forward for error handling situations. For example, this:

void foo()
{
    char *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
    
    p1 = malloc(1000);
    if (!p1) {
        perror("malloc failed");
        return;
    }
    p2 = malloc(1000);
    if (!p2) {
        perror("malloc failed");
        free(p1);
        return;
    }
    p3 = malloc(1000);
    if (!p3) {
        perror("malloc failed");
        free(p2);
        free(p1);
        return;
    }
    p4 = malloc(1000);
    if (!p4) {
        perror("malloc failed");
        free(p3);
        free(p2);
        free(p1);
        return;
    }

    // Do something with p1, p2, p3, p4

    free(p4);
    free(p3);
    free(p2);
    free(p1);
}

Can be translated to this:

void foo()
{
    char *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
    
    p1 = malloc(1000);
    if (!p1) {
        perror("malloc failed");
        goto err0;
    }
    p2 = malloc(1000);
    if (!p2) {
        perror("malloc failed");
        goto err1;
    }
    p3 = malloc(1000);
    if (!p3) {
        perror("malloc failed");
        goto err2;
    }
    p4 = malloc(1000);
    if (!p4) {
        perror("malloc failed");
        goto err3;
    }

    // Do something with p1, p2, p3, p4

    free(p4);
err3:
    free(p3);
err2:
    free(p2);
err1:
    free(p1);
err0:
    return;
}

This puts all of the cleanup code in one place.

Related